【问题标题】:What exactly is ListView.RetrieveVirtualItem Event - C#究竟什么是 ListView.RetrieveVirtualItem 事件 - C#
【发布时间】:2012-05-17 18:18:24
【问题描述】:

对于Winforms App中的Virtual ListView控件,RetrieveVirtualItem事件的ALL的作用是什么?

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

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

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

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

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

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

【问题讨论】:

    标签: c# winforms listview .net-3.5


    【解决方案1】:

    虚拟 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。

    希望对您有所帮助... 祝你好运

    【讨论】:

      【解决方案2】:

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

      你必须在你的排序方法中自己编程:

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

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

      【讨论】:

        【解决方案3】:

        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),可在其中找到更多详细信息。

        【讨论】:

        • 您说“如果您不处理 RetrieveVirtualItem 事件,则不会将 ListViewItems 添加到您的 ListView 中”,那么相反,是否意味着所有项目都由该事件添加?似乎没有,因为它只与myCache[e.ItemIndex - firstItem] 一起玩。
        • 是的,所有项目(当列表视图处于虚拟模式时)都将被此事件添加。该方法不仅依赖于从 myCache 获取项目,就好像执行 else 子句中的代码一样,一个新项目被实例化并分配给事件 args (e.Item=new ListViewItem())。另一个事件 CacheVirtualItems 是依赖于管理缓存
        猜你喜欢
        • 1970-01-01
        • 2014-10-28
        • 2012-08-27
        • 2010-11-12
        • 2011-03-18
        • 2011-01-22
        • 1970-01-01
        相关资源
        最近更新 更多