Kor*_*tak 2 wpf scroll listbox visible
我有一个叫做Book的课;
class Book
{
public string Name { get; set; }
public string Author { get; set; }
public int PagesCount { get; set; }
public int Category { get; set; }
}
Run Code Online (Sandbox Code Playgroud)
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
在尝试找出类似的东西后,我想我会在这里分享我的结果(因为它似乎比其他响应更容易):
我从这里得到的简单可见性测试.
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);
}
Run Code Online (Sandbox Code Playgroud)
之后,您可以遍历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;
}
Run Code Online (Sandbox Code Playgroud)
然后,这将包含列表框中当前显示的项目列表(包括通过滚动或类似内容隐藏的项目).