带有 ListBox 的 WPF ListBox - UI 虚拟化和滚动 [英] WPF ListBox with a ListBox - UI Virtualization and Scrolling

查看:23
本文介绍了带有 ListBox 的 WPF ListBox - UI 虚拟化和滚动的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我的原型显示包含页面"的文档"由缩略图表示.每个文件可以有任意页数.例如,可能有1000 个文档,每个文档 5 页,或 5 个文档,每个文档 1000 页每个,或介于两者之间.文档不包含其他文档.在我的 xaml 标记中,我有一个 ListBox,它的 ItemsTemplate引用了一个也有 ListBox 的 innerItemsTemplate.我想要2级选定项目,以便我可以执行各种操作在文档或页面上(删除、合并、移动到新位置等).innerItemsTemplate ListBox 使用 WrapPanel 作为 ItemsPanelTemplate.

My prototype displays "documents" that contain "pages" that are represented by thumbnail images. Each document can have any number of pages. For example, there might be 1000 documents with 5 pages each, or 5 documents with 1000 pages each, or somewhere inbetween. Documents do not contain other documents. In my xaml markup I have a ListBox, whose ItemsTemplate references an innerItemsTemplate that also has a ListBox. I want the 2 levels of selected items so that I can perform various operations on documents or pages (delete, merge, move to new location, etc). The innerItemsTemplate ListBox uses a WrapPanel as the ItemsPanelTemplate.

对于我有大量文档的场景每页(例如,10000 个文档,每页 5 页),滚动非常感谢 VirtualizingStackPanel 的 UI 虚拟化.但是,如果我有大量页面,我会遇到问题.一份文件有 1000 个页面一次只会显示大约 50 个(无论屏幕适合什么),当我向下滚动时,外部 ListBox 移动到下一个文档,跳过 950页面左右是不可见的.除此之外,没有VirtualzingWrapPanel 所以应用内存确实增加了.

For the scenario where I have a large number of documents with a few pages each (say, 10000 documents with 5 pages each), the scrolling works great thanks to the UI Virtualization by the VirtualizingStackPanel. However, I have problems if I have a large number of pages. A document with 1000 pages will only display about 50 at a time (whatever fits on the screen), and when I scroll down, the outer ListBox moves to the next document, skipping the 950 pages or so that were not visible. Along with that, there is no VirtualzingWrapPanel so the app memory really increases.

我想知道我是否以正确的方式处理这件事,尤其是因为这有点难以解释!我希望能够显示10000 个文档,每个文档 1000 页(仅显示适合屏幕的内容),使用 UI 虚拟化,并且还可以平滑滚动.

I'm wondering if I am going about this the right way, especially since it is sort of difficult to explain! I would like to be able to display 10000 documents with 1000 pages each (only showing whatever fits on the screen), using UI Virtualization, and also smooth scrolling.

如何确保滚动浏览文档中的所有页面在它显示下一个文档之前,仍然保持 UI 虚拟化?滚动条似乎只移动到下一个文档.

How can I make sure the scrolling moves through all of the pages in document before it displays the next document, and still keep UI virtualization? The scrollbar seems to only move to the next document.

表示文档"和页面"是否合乎逻辑 -我目前在 ListBox 中使用 ListBox 的方法?

Does it seem logical to represent "documents" and "pages" - with my current method of using a ListBox within a ListBox?

我非常感谢您的任何想法.谢谢.

I would very much appreciate any ideas you have. Thank You.

推荐答案

这里的答案令人惊讶:

  • 如果您使用 ItemsControlListBox,您将获得您所遇到的行为,即控件按项目"滚动,因此您可以一次跳过整个文档,但是
  • 如果您改用 TreeView,控件将平滑滚动,因此您可以滚动浏览文档并进入下一个文档,但它仍然可以虚拟化.
  • If you use ItemsControl or ListBox you will get the behavior you are experiencing, where the control scrolls "by item" so you jump over a whole document at once, BUT
  • If you use TreeView instead, the control will scroll smoothly so you can scroll through your document and into the next one, but it will still be able to virtualize.

我认为 WPF 团队选择这种行为的原因是 TreeView 通常具有大于可见区域的项目,而通常 ListBoxes 没有.

I think the reason the WPF team chose this behavior is that TreeViewcommonly has items that are larger than the visible area, whereas typically ListBoxes don't.

在任何情况下,通过简单地修改 <代码>ItemContainerStyle.这非常简单.您可以滚动自己的模板,也可以直接从系统主题文件中复制相应的模板.

In any case, it is trivial in WPF to make a TreeView look and act like a ListBox or ItemsControl by simply modifying the ItemContainerStyle. This is very straightforward. You can roll your own or just copy over the appropriate template from the system theme file.

所以你会有这样的东西:

So you will have something like this:

<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>

让基于像素的滚动和 ListBox 样式的多选协同工作

如果您使用此技术进行基于像素的滚动,则显示文档的外部 ItemsControl 不能是 ListBox(因为 ListBox 不是 TreeView 或 TreeViewItem 的子类).因此,您失去了 ListBox 的所有多选支持.据我所知,如果不为其中一个功能添加一些您自己的代码,就无法同时使用这两个功能.

If you use this technique to get pixel-based scrolling, your outer ItemsControl which shows the documents cannot be a ListBox (because ListBox is not a subclass of TreeView or TreeViewItem). Thus you lose all of ListBox's multiselect support. As far as I can tell, there is no way to use these two features together without including some of your own code for one feature or the other.

如果您需要在同一个控件中使用两组功能,您基本上有几种选择:

If you need both sets of functionality in the same control, you have basically several options:

  1. 自己在 TreeViewItem 的子类中实现多选.使用 TreeViewItem 而不是 TreeView 作为外部控件,因为它允许选择多个子控件.在 ItemsContainerStyle 内的模板中:在 ContentPresenter 周围添加 CheckBox,模板将 CheckBox 绑定到 IsSelected,并使用控件模板设置 CheckBox 的样式以获得您想要的外观.然后添加您自己的鼠标事件处理程序来处理多选的 Ctrl-Click 和 Shift-Click.

  1. Implement multi-selection yourself in a subclass of TreeViewItem. Use TreeViewItem instead of TreeView for the outer control, since it allows multiple children to be selected. In the template inside ItemsContainerStyle: Add a CheckBox around the ContentPresenter, template bind the CheckBox to IsSelected, and style the CheckBox with control template to get the look you want. Then add your own mouse event handlers to handle Ctrl-Click and Shift-Click for multiselect.

在 VirtualizingPanel 的子类中自己实现像素滚动虚拟化.这相对简单,因为 VirtualizingStackPanel 的大部分复杂性都与非像素滚动和容器回收有关.Dan Crevier 的博客 提供了一些有助于理解 VirtualizingPanel 的有用信息.

Implement pixel-scrolled virtualization yourself in a subclass of VirtualizingPanel. This is relatively simple, since most of VirtualizingStackPanel's complexity is related to non-pixel scrolling and container recycling. Dan Crevier's Blog has some useful infromation for understanding VirtualizingPanel.

这篇关于带有 ListBox 的 WPF ListBox - UI 虚拟化和滚动的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆