Rob*_*ler 26 wpf virtualization user-interface scroll listbox
我的原型显示"文档",其中包含由缩略图图像表示的"页面".每个文档可以包含任意数量的页面.例如,可能有1000个文档,每个文档有5个页面,或者5个文档,每个文档有1000个页面,或者介于两者之间.文件不包含其他文件.在我的xaml标记中,我有一个ListBox,其ItemsTemplate
引用的innerItemsTemplate也有一个ListBox.我想要2级选定的项目,以便我可以对文档或页面执行各种操作(删除,合并,移动到新位置等).innerItemsTemplate ListBox使用a WrapPanel作为ItemsPanelTemplate.
对于我有大量文档的情况,每个文档都有几个页面(比如10000个文档,每个页面有5个页面),滚动工作非常好,这要归功于UI虚拟化VirtualizingStackPanel.但是,如果我有大量的页面,我会遇到问题.具有1000页的文档一次仅显示约50个(无论何种适合屏幕),当我向下滚动时,外部ListBox移动到下一个文档,跳过不可见的950页左右.除此之外,VirtualzingWrapPanel应用程序内存确实没有
增加.
我想知道我是否以正确的方式解决这个问题,特别是因为它有点难以解释!我希望能够显示10000个文档,每个文档1000页(仅显示适合屏幕的任何内容),使用UI虚拟化,以及平滑滚动.
如何在显示下一个文档之前确保滚动在文档中的所有页面中移动,并且仍然保持UI虚拟化?滚动条似乎只移动到下一个文档.
表示"文档"和"页面"似乎合乎逻辑 - 使用我当前ListBox在a 中使用a的方法ListBox?
我非常感谢你的任何想法.谢谢.
Sam*_*ack 44
如果您准备使用反射来访问VirtualizingStackPanel的私有功能,则可以在WPF 4.0中实现平滑滚动VirtualizingStackPanel而不牺牲虚拟化.您所要做的就是将VirtualizingStackPanel的私有IsPixelBased属性设置为true.
请注意,在.Net 4.5中,不需要这个hack,因为您可以设置VirtualizingPanel.ScrollUnit ="Pixel".
为了让它变得非常简单,这里有一些代码:
public static class PixelBasedScrollingBehavior
{
public static bool GetIsEnabled(DependencyObject obj)
{
return (bool)obj.GetValue(IsEnabledProperty);
}
public static void SetIsEnabled(DependencyObject obj, bool value)
{
obj.SetValue(IsEnabledProperty, value);
}
public static readonly DependencyProperty IsEnabledProperty =
DependencyProperty.RegisterAttached("IsEnabled", typeof(bool), typeof(PixelBasedScrollingBehavior), new UIPropertyMetadata(false, HandleIsEnabledChanged));
private static void HandleIsEnabledChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
var vsp = d as VirtualizingStackPanel;
if (vsp == null)
{
return;
}
var property = typeof(VirtualizingStackPanel).GetProperty("IsPixelBased",
BindingFlags.NonPublic | BindingFlags.Instance);
if (property == null)
{
throw new InvalidOperationException("Pixel-based scrolling behaviour hack no longer works!");
}
if ((bool)e.NewValue == true)
{
property.SetValue(vsp, true, new object[0]);
}
else
{
property.SetValue(vsp, false, new object[0]);
}
}
}
Run Code Online (Sandbox Code Playgroud)
例如,要在ListBox上使用它,您可以:
<ListBox>
<ListBox.ItemsPanel>
<ItemsPanelTemplate>
<VirtualizingStackPanel PixelBasedScrollingBehavior.IsEnabled="True">
</VirtualizingStackPanel>
</ItemsPanelTemplate>
</ListBox.ItemsPanel>
</ListBox>
Run Code Online (Sandbox Code Playgroud)
Ray*_*rns 25
这里的答案令人惊讶:
ItemsControl或者ListBox你会得到你正在经历的行为,控件滚动"按项目",这样你就可以一次跳过整个文档,但是TreeView,控件将平滑滚动,以便您可以滚动文档并进入下一个文档,但它仍然可以虚拟化.我认为WPF团队选择此行为的原因TreeView通常是项目大于可见区域,而通常情况下ListBox不会.
在任何情况下,在WPF中TreeView看起来像一个ListBox或ItemsControl简单地修改它是微不足道的ItemContainerStyle.这非常简单.您可以自己滚动,也可以只从系统主题文件中复制相应的模板.
所以你会有这样的事情:
<TreeView ItemsSource="{Binding documents}">
<TreeView.ItemsPanel>
<ItemsPanelTemplate>
<VirtualizingStackPanel />
</ItemsPanelTemplate>
</TreeView.ItemsPanel>
<TreeView.ItemContainerStyle>
<Style TargetType="{x:Type TreeViewItem}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type TreeViewItem}">
<ContentPresenter /> <!-- put your desired container style here with a ContentPresenter inside -->
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</TreeView.ItemContainerStyle>
<TreeView.ItemTemplate>
<DataTemplate TargetType="{x:Type my:Document}">
<Border BorderThickness="2"> <!-- your document frame will be more complicated than this -->
<ItemsControl ItemsSource="{Binding pages}">
...
</ItemsControl>
</Border>
</DataTemplate>
</TreeView.ItemTemplate>
</TreeView>
Run Code Online (Sandbox Code Playgroud)
使基于像素的滚动和ListBox样式的多选项一起工作
如果使用此技术来获取基于像素的滚动,则显示文档的外部ItemsControl不能是ListBox(因为ListBox不是TreeView或TreeViewItem的子类).因此,您将失去所有ListBox的多选支持.据我所知,没有办法将这两个功能结合使用,而不包括一些功能或其他功能的代码.
如果在同一个控件中需要两组功能,基本上有几个选项:
在TreeViewItem的子类中自己实现多选.使用TreeViewItem而不是TreeView作为外部控件,因为它允许选择多个子项.在ItemsContainerStyle中的模板中:在ContentPresenter周围添加一个CheckBox,模板将CheckBox绑定到IsSelected,并使用控件模板为CheckBox设置样式以获得所需的外观.然后添加您自己的鼠标事件处理程序以处理Ctrl-Click和Shift-Click以进行多选.
在VirtualizingPanel的子类中自己实现像素滚动虚拟化.这相对简单,因为VirtualizingStackPanel的大部分复杂性与非像素滚动和容器回收有关. Dan Crevier的博客对于理解VirtualizingPanel有一些有用的信息.
Bod*_*man 16
.NET 4.5现在拥有该VirtualizingPanel.ScrollUnit="ScrollUnit"属性.我只是将我的一个TreeView转换为ListBox,性能明显更好.
更多信息请访问:http://msdn.microsoft.com/en-us/library/system.windows.controls.virtualizingpanel.scrollunit(v = vs.110).aspx
这对我有用.似乎有几个简单的属性可以做到(.NET 4.5)
<ListBox
ItemsSource="{Binding MyItems}"
VirtualizingStackPanel.IsVirtualizing="True"
VirtualizingStackPanel.ScrollUnit="Pixel"/>
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
19650 次 |
| 最近记录: |