我有一个名为Book的课程;

class Book
{
    public string Name { get; set; }
    public string Author { get; set; }
    public int PagesCount { get; set; }
    public int Category { get; set; }
}

ListBox显示Books列表,并且ItemTemplate已被修改,以便直观地表示Book。文本显示了书的名称,作者和页数。然而,类别由某种颜色表示(例如,历史是蓝色,浪漫是红色等)。现在,文本具有OuterGlowBitmap效果和从Category(int)到适当Color的值转换器。所有内容都绑定在DataTemplate for ListBoxItem中。从技术上讲,一切正常。

但问题在于性能。似乎outerGlow位图效果在处理器上很重,所以当我有大约500本书的列表时,从数据库中检索数据需要大约500ms,但实际将项目加载到ListBox大约需要10秒。即使加载完成,滚动也非常滞后。我试图将VirtualizingStackPanel.IsVirtualizing设置为True,但无济于事。 (在任何给定时间,数据库中可以包含的最大书籍数量约为30000。)

然而,即使列表框中有超过100个项目,人类思维也无法快速处理,因此我不打算加载并向用户列出所有搜索到的书籍。这就是为什么我创建了一个包装器导航类BookNavigator,它实际上将列表框绑定到它的ObservableCollection对象。所有书籍都被加载到这个BookNavigator中,但它们中只有X个显示在列表框中(通过将它们添加到observableCollection)。

这个问题是我希望显示的书籍数量足够小,以便列表框不显示滚动条,所以我可以实现我自己的滚动方法(第一个,上一个,下一个,最后一个,或者只是我自己的滚动条,没关系)。

如何计算要显示的项目数,以便不显示滚动条?

弹出两个问题: - 调整应用程序大小可以更改列表框的大小 - 并非所有列表框项目都具有相同的高度(取决于作者的数量)。

有没有办法实现我想做的事情?


编辑(作为对Martin Harris的回复)

代码Martin Harris建议的问题是foreach循环使用FrameworkElement,但是listbox填充了Book类型的对象,它不从FrameworkElement继承,也没有任何其他计算高度的方法。 ListBoxItem的根元素是一个网格,所以也许可以检索这个网格,但我不知道该怎么做?

有没有办法获得为表示列表框项而创建的实际UI元素?


修改

我发现这个Q / A似乎是我需要的...... ItemContainerGenerator

有帮助吗?

解决方案 4

可以在此隐含地找到解决方案: 解决方案

其他提示

在尝试找出类似的东西之后,我想我会在这里分享我的结果(因为它似乎比其他回复更容易):

我从此处

private static bool IsUserVisible(FrameworkElement element, FrameworkElement container)
{
    if (!element.IsVisible)
        return false;

    Rect bounds =
        element.TransformToAncestor(container).TransformBounds(new Rect(0.0, 0.0, element.ActualWidth, element.ActualHeight));
    var rect = new Rect(0.0, 0.0, container.ActualWidth, container.ActualHeight);
    return rect.Contains(bounds.TopLeft) || rect.Contains(bounds.BottomRight);
}

之后,您可以遍历listboxitems并使用该测试来确定哪些是可见的。此列表的计数将为您提供列表框中可见项目的数量。

private List<object> GetVisibleItemsFromListbox(ListBox listBox, FrameworkElement parentToTestVisibility)
{
    var items = new List<object>();

    foreach (var item in PhotosListBox.Items)
    {
        if (IsUserVisible((ListBoxItem)listBox.ItemContainerGenerator.ContainerFromItem(item), parentToTestVisibility))
        {
            items.Add(item);
        }
        else if (items.Any())
        {
            break;
        }
    }

    return items;
}

这将包含列表框中当前显示的项目列表(包括通过滚动或类似内容隐藏的项目)。

在将它们添加到列表框之前,您是否可能能够计算出所有书籍的大小(可能通过在代码中解析和填充模板XAML然后向外部控件询问其大小)这将是很多工作,没有太大的收获。难道你不能简单地选择一些足以填充列表框的书籍,但不能减少渲染速度并关闭滚动条吗?这可能仍然与列表框的大小相关联,因此随着项目的增加,添加了更多项目,但添加一些额外项目的性能成本应该低于再次计算所有大小的成本。

快速示例:假设一位作者的书的大小为150像素。您可以采用列表框的大小并将其除以125以粗略估计将在球场内的项目数量,但计算成本不高。你要避免的是太少的物品,因为这会留下空的空间。


根据您的评论进行编辑。

在这种情况下,您可以将项目添加到列表框中(使用上面的方法进行近距离猜测),然后计算最后一个完全可见的项目,然后删除多余的项目。

此扩展方法将获取完整显示在列表框中的最后一个元素,如果没有可见的项目,则返回null:

public static class ListBoxExtensions
{
    public static FrameworkElement GetLastItem(this ListBox listBox)
    {
        double height = listBox.ActualHeight;

        double currentHeight = 0;
        FrameworkElement previous = null;

        foreach (FrameworkElement item in listBox.Items)
        {
            currentHeight += item.ActualHeight;
            if (currentHeight > height)
            {
                return previous;
            }

            previous = item;
        }

        return previous;
    }
}

如果列表变大,那么您可以向集合中添加足够的项目以填补空白并重新运行该过程。

“如何计算要显示的项目数,以便不显示滚动条? &QUOT;

简答:(listBox1.Height / listBox1.ItemHeight)

这为您提供了显示/可用行数,因此您只能读取此行数并填充所有列表框。

现在,演示:

        int listbox_total_visible_lines = 2;
        listBox1.Height = (listbox_total_visible_lines + 1) * listBox1.ItemHeight;
        listBox1.Items.Add("um");
        listBox1.Items.Add("dois");
        listBox1.Items.Add("tres");
        listBox1.Items.Add("quatro");
        listBox1.Items.Add("cinco");
        listBox1.SelectedIndex = listBox1.Items.Count - 1;
        this.Text = (listBox1.Height/ listBox1.ItemHeight).ToString();

这个例子让你选择可见的项目数,所以它是可以显示的实际数字。因此,您只需添加“listbox_total_visible_items”。项目和列表框将已满,不显示滚动条。

代码说明:

  1. listbox_total_visible_items包含要显示的行数

  2. 设置列表框,大小合适,仅限2行

  3. 3-7。添加一些行

    1. 转到最后一行,只是为了好玩

    2. 在表单文本栏上显示列表框行数,基于列表框高度除以每个项目的大小。

    3. 就是这样。

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top