C# listview虚拟列表,例如ItemIndex崩溃!

C# listview虚拟列表,例如ItemIndex崩溃!,c#,listview,listviewitem,C#,Listview,Listviewitem,问题可能很简单,帖子比我希望的要长,但我已经尝试提供尽可能多的信息和细节。 我没有编写这个GUI应用程序,也没有设计它,但和我们大多数人一样,我继承了它 它有一个(常规的)列表视图,实际上该应用程序有几个列表视图,不确定这是否重要。 因为到达这个列表视图(屏幕/表单)的项目数量可能会达到非常大的10K+,我决定将其转换为虚拟列表,但是我遇到了一些早期问题 最大的问题之一是,通过点击表单上的按钮来异步填充项。 当它们到达时(从服务/网络/数据库),这些项目将内置到ListViewItem中,并添加

问题可能很简单,帖子比我希望的要长,但我已经尝试提供尽可能多的信息和细节。 我没有编写这个GUI应用程序,也没有设计它,但和我们大多数人一样,我继承了它

它有一个(常规的)列表视图,实际上该应用程序有几个列表视图,不确定这是否重要。 因为到达这个列表视图(屏幕/表单)的项目数量可能会达到非常大的10K+,我决定将其转换为虚拟列表,但是我遇到了一些早期问题

最大的问题之一是,通过点击表单上的按钮来异步填充项。 当它们到达时(从服务/网络/数据库),这些项目将内置到ListViewItem中,并添加到作为ArrayList的someListItems中

在我的RetrieveVirtualItem方法中,我需要处理列表为空以及我已经有了东西(在按下按钮之后)以及我撞到墙上(没有双关语)这两种情况 使用以下代码行:

if ( someListItems.Count > e.ItemIndex ) 
它基本上会导致(不知道为什么)调用主窗体上的Dispose方法,从而导致整个应用程序严重崩溃。但是只有当我点击表单和列表时才会发生这种情况。如果表单刚刚加载并填充,就可以了。鼠标左键点击的那一秒,砰

我花了几个小时才发现上面这一行是罪魁祸首,因为调用堆栈没有很明显地指出这一点,我又花了一分钟才发现
e.ItemIndex
是罪魁祸首。但是为什么???我 n msdn示例他们访问e.ItemIndex来执行测试,看起来很好

在窗体的构造函数中设置虚拟模式:

myListView.VirtualMode = true;
VirtualListSize在数据异步到达后立即设置:

 myListView.VirtualListSize = someArrayList.Count;
这是我的RetrieveVirtualItem实现:

private void blah_RetrieveVirtualItem( object sender, RetrieveVirtualItemEventArgs e )
{
 // someListItems is an ArrayList that is created when the object/class loads..and populated with ListViewItems.
// i.e. private ArrayList someListItems = new ArrayList();
// it is populated asynchronously by hitting a button on the form, hence it's empty when the form loads..
      if ( someListItems.Count <= 0 )
      {
         e.Item = new ListViewItem( "" );
         e.Item.SubItems.Add( "" );
         e.Item.SubItems.Add( "" );
      }
      else
      {
// the of code below is the problem, and more specifically - e.ItemIndex causes somehow to call Dispose on the main form..
// the reason I have this code is because if I take it out, all items will show up, no problem, but it will crash when I try to scroll down..
// with message like this:
// Index was out of range. Must be non-negative and less than the size of the collection. Parameter name: index

   if ( someListItems.Count > e.ItemIndex )             
   {
   // took out my code out to eliminate possibility that it's my code. :)
    int x = e.ItemIndex * e.ItemIndex;
    e.Item = new ListViewItem( x.ToString() );

   // but I had something like that just for a test:
   //    ListViewItem item = ( ListViewItem )someListItems[e.ItemIndex];
   //    e.Item = item;
   // remember that someListItems already has ListViewItems
   }
  }       
 } 
还有另一个问题是,除非我拿出以下物品,否则这些物品根本不会出现:

if ( someListItems.Count > e.ItemIndex ) 
但是当我尝试滚动时,我遇到了索引超出范围的问题


更新:

我注意到,如果我设置虚拟列表的大小,只有在循环完成后,因此在开始时它是零(0)(我总是可以将其重置为零),那么一切都可以工作,不需要检查大小,我所要做的就是:

在循环之后:
private void ExampleMethod\u populatesHomeArrayList(ArrayList ar)

我要感谢汉斯·帕桑特注意到这种差异。 因此,这是完整的,现在(我相信我会添加一些代码或更改,因为我想添加一些缓存,但至少我有一些

private void blah_RetrieveVirtualItem( object sender, RetrieveVirtualItemEventArgs e )
 {
   e.Item = ( ListViewItem )someListItems[e.ItemIndex];
}
我唯一不确定Hans Passant提到的是:“这个事件处理程序从不分配ListViewItem真的是不好的。”我不确定自己是否理解,因为ListViewItems已分配并插入到someListItems数组中。我确实尝试过,以前也尝试过

另外,我在想,如果有人对这个想法有意见,我将不胜感激: 创建一个单独的对象来保存SomeObject的所有属性,或者将SomeObject插入列表并根据需要创建新的ListViewItems? 例如:

private void blah_RetrieveVirtualItem( object sender, RetrieveVirtualItemEventArgs e )
     {
        // that list would be build sometime during the loop iteration in
        // (I'm using the original method name mentioned way above in this post)
        // ExampleMethod_That_PopulatesSomeArrayList(ArrayList ar)

        SomeObject o = listOfObjects[e.ItemIndex];
        e.Item = new ListViewItem();
        e.Item.SubItems.Add(o.prop1);
        e.Item.SubItems.Add(o.prop2);
        e.Item.SubItems.Add(o.prop3);         
    } 

要回答此问题,虚拟列表正在崩溃,因为VirtualListSize设置不正确。 基本上,为了帮助这里的其他人,如果您有一个虚拟列表,请始终确保VirtualListSize与您试图显示的项目的实际数量相对应。如果没有,所有的问题都会解决。如果您确实更新、删除、添加任何内容,则需要将VirtualListSize重置为正确的数字


我最终从ListView派生并将listviewitems存储在一个数组中。

异常和堆栈跟踪是什么?
private void blah_RetrieveVirtualItem( object sender, RetrieveVirtualItemEventArgs e )
 {
   e.Item = ( ListViewItem )someListItems[e.ItemIndex];
}
private void blah_RetrieveVirtualItem( object sender, RetrieveVirtualItemEventArgs e )
     {
        // that list would be build sometime during the loop iteration in
        // (I'm using the original method name mentioned way above in this post)
        // ExampleMethod_That_PopulatesSomeArrayList(ArrayList ar)

        SomeObject o = listOfObjects[e.ItemIndex];
        e.Item = new ListViewItem();
        e.Item.SubItems.Add(o.prop1);
        e.Item.SubItems.Add(o.prop2);
        e.Item.SubItems.Add(o.prop3);         
    }