首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >列表视图虚拟列表,e.ItemIndex崩溃!

列表视图虚拟列表,e.ItemIndex崩溃!
EN

Stack Overflow用户
提问于 2010-10-08 15:53:21
回答 1查看 1.6K关注 0票数 0

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

它有一个(常规的) ListView,实际上这个应用程序有几个ListView,还不确定这是否重要。由于到达这个ListView (屏幕/表单)的条目#可以获得非常大的10K+,所以我决定将其转换为虚拟列表,但是我遇到了一些早期问题。

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

在我的RetrieveVirtualItem方法中,我需要处理两种情况:列表是空的,当我已经有东西时(在按钮被点击之后),也就是我用下面的代码行撞墙(没有双关语)的时候:

代码语言:javascript
复制
if ( someListItems.Count > e.ItemIndex ) 

它基本上会导致(不知道为什么)调用主窗体上的Dispose方法,从而导致整个应用程序崩溃。但是!!,只有当我单击表单和列表时才会发生这种情况。如果表单是刚刚加载和填充,它是fine..the的第二次点击鼠标左键,砰!

我花了几个小时才发现上面的那条线是罪魁祸首,因为调用堆栈并没有很明显地指出这一点,再过一分钟就发现e.ItemIndex是罪魁祸首。但为什么?在msdn示例中,他们访问e.ItemIndex来执行测试,这似乎很好。

虚拟模式在表单的构造函数中设置:

代码语言:javascript
复制
myListView.VirtualMode = true;

VirtualListSize是在数据异步到达之后设置的:

代码语言:javascript
复制
 myListView.VirtualListSize = someArrayList.Count;

这是我的RetrieveVirtualItem实现:

代码语言:javascript
复制
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
   }
  }       
 } 

异步调用、创建ListViewItems和填充someListItems的方法如下所示:

代码语言:javascript
复制
private void ExampleMethod_That_PopulatesSomeArrayList(ArrayList ar)
{
 //Im only showing more essential code..

  SomeArrayList.Items.Clear();   
  myListView.VirtualListSize = ar.Count;
  foreach ( SomeObject o in ar )
  {
    ListViewItem lvi = new ListViewItem( SomeObject.somePropertyID, 0 );  
// I've tried changing the above line to: lvi = new ListViewItem( SomeObject.somePropertyID, 0 );  // and having the ListViewItem lvi on the class level. i.e private ListViewItem lvi 
// didn't help.. :(

    lvi.SubItems.Add( o.someProperty1 );
    lvi.SubItems.Add( o.someProperty2 );
// there's quite few of these subitems..2 is enough for this example...
   }

 // the orignal code, before I changed it to virtual list was adding the items somewhere here..after finished looping, now I'm just trying to reuse that array of ListViewItems.
}

还有另一个问题,除非我拿出以下内容,否则这些物品根本不会出现:

代码语言:javascript
复制
if ( someListItems.Count > e.ItemIndex ) 

但是,当我尝试滚动时,我会体验到超出范围问题的指数。

更新:

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

循环之后:private void ExampleMethod_That_PopulatesSomeArrayList(ArrayList ar)

代码语言:javascript
复制
this.myListView.VirtualListSize = someListItems.Count;

我要感谢Hans Passant注意到了这一差异。这是完整的,目前(我肯定我会添加一些代码或更改,因为我想添加一些缓存,但至少我有一些.

代码语言:javascript
复制
private void blah_RetrieveVirtualItem( object sender, RetrieveVirtualItemEventArgs e )
 {
   e.Item = ( ListViewItem )someListItems[e.ItemIndex];
}

我不确定汉斯·帕桑特提到的唯一一件事是:ListViewItems“这个事件处理程序永远不分配ListViewItem真的是不行的。",我不确定是否理解,因为是分配并插入到someListItems数组中的。我确实有一次尝试,我以前也有过。

此外,我还在想,我希望有人能对这个想法提出意见:创建一个单独的对象,该对象将保存SomeObject的所有属性,或者将SomeObject(s)插入到列表中,并根据需要创建新的ListViewItems?

代码语言:javascript
复制
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);         
    } 
EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2010-10-29 16:49:46

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

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

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/3892242

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档