2

对于 Winforms 应用程序中的虚拟 ListView 控件,RetrieveVirtualItem 事件的所有功能是什么?

场景:有一个 Dictionary 对象充当我的 ListView 缓存。它的项目显示在 ListView 上。单击列时,缓存字典在内存中排序,ListView 被 Refresh()ed。UI上的效果,ListView排序不错。:)

但我想了解 RetrieveVirtualItem 事件的作用是什么,它在 Refresh() 上触发。

在 RetrieveVirtualItem 事件处理程序 [ 别人的代码,:( ] 中,完成了以下操作:

  1. 基于RetrieveVirtualItemEventArgs.ItemIndex, 从 Cache 中获取消息
  2. Set RetrieveVirtualItemEventArgs.Item= 上面检索到的项目

似乎在事件处理程序中所做的事情很重要,因为如果我把它拿出来,ListView 会哭。这次活动的意义何在?

编辑 或者让我重新表述这个问题......我担心的是,为什么在排序(和RetrieveVirtualItem事件处理程序)之后,所选项目仍保留在排序前的位置。即,如果我选择项目#5 并排序,并且如果排序使该项目成为最后一项,我希望在排序之后选择最后一项。但在我的情况下,排序后选择了第 5 个项目。那么RetrieveVirtualItemWRT 选中项的默认行为是什么?

4

3 回答 3

4

虚拟 ListView 应该只为屏幕上当前可见的行调用 RetreiveVirtualItem。

例如,当您在 ListView 中导航时,按下 page down 键,ListView 将计算现在应该是顶行的索引,然后调用 RetrieveVirtualItem 以便您的代码可以提供要在每个行索引处使用的项目.

除非您缓存或以其他方式存储您通过 RetrieveVirtualItem 提供的项目,否则一旦它们被滚动出列表视图,它们将不再存在。

这就是 VirtualListView 中的 Virtual 的含义——没有任何真实的行,这些行是虚拟的。这就是它如何显示包含数十万行的列表的方式 - 因为它实际上只会包含屏幕上可见的行数。

实际上,ListView 就像一个窗口,在您的内部数据列表中上下移动 - RetreiveVirtualItem 方法是它调用的方法,以便在移动时将项目移动到该窗口中。它说,嘿,我刚搬到第 15 行 - 给我该行的项目。它将继续为每个可见的行索引调用 RetreiveVirtualItem。如果 ListView 在屏幕上的高度为 5 行,您将收到 5 次对 RetrieveVirtualItem 的调用 - 即使支持 listview 的实际数据有 3000 个项目。每次 ListView 的顶行发生变化(由于导航),您将收到 5 次 RetrieveVirtualItem 调用(并非总是如此,但这是正确的想法 - 例如,如果您向下滚动一行,

我想如果我们假设 ListView 在显示器上只有一行高(这意味着在屏幕上实际上只有一行是可见的),解释起来可能会更容易 - 当您上下移动 ListView 数据列表时(即用户导航 ListView),它每次移动到新行时都会准确地调用一次 RetrieveVirtualItem。

希望有帮助......祝你好运

于 2012-12-10T22:28:32.417 回答
2

RetrieveVirtualItem 事件仅在 ListView 进入虚拟模式时使用。它不是在 Items 集合中保留 ListViewItems(当不在虚拟模式下时),而是在需要时动态创建 ListViewItems。

如果您不处理 RetrieveVirtualItem 事件,则不会将任何 ListViewItems 添加到您的 ListView。我附上了一些用于处理事件的典型方法的示例代码:

  //Dynamically returns a ListViewItem with the required properties; in this case, the square of the index.
void listView1_RetrieveVirtualItem(object sender, RetrieveVirtualItemEventArgs e)
    {
        //Check if cache has been instantiated yet, and if so, whether the item corresponding to the index requested has been added to the cache already
        if (myCache != null && e.ItemIndex >= firstItem && e.ItemIndex < firstItem + myCache.Length)
        {
            //Return cached item for index
            e.Item = myCache[e.ItemIndex - firstItem];
        }
        else
        {
            //When item not in cache (or cache not available) return a new ListViewItem
            int x = e.ItemIndex * e.ItemIndex;
            e.Item = new ListViewItem(x.ToString());
        }
    }

此示例取自 MSDN ( http://msdn.microsoft.com/en-us/library/system.windows.forms.listview.virtualmode(v=vs.90).aspx ),可以找到更多详细信息。

于 2012-05-09T09:23:45.670 回答
2

虚拟列表视图仅处理索引。因此,如果在排序之前选择了第 5 项,则在排序之后仍然会选择第 5 项。控件本身无法知道以前在第 5 行的数据现在在第 1 行。

您必须在排序方法中为自己编程:

  1. SelectedItems记住选择了哪些项目(记住:在虚拟模式下不能使用属性)
  2. 做排序
  3. 找到以前选择的项目的索引现在生效
  4. 选择那些索引

您可以在ObjectListView中看到所有这些操作——标准 .NET ListView 的包装器。

于 2012-05-11T05:59:52.727 回答