【问题标题】:how to set the top item property of listviewitem when it is in virtual mode?listviewitem在虚拟模式下如何设置top item属性?
【发布时间】:2015-02-08 04:34:10
【问题描述】:
public new int VirtualListSize
    {
        get { return base.VirtualListSize; }
        set
        {
            // If the new size is smaller than the Index of TopItem, we need to make
            // sure the new TopItem is set to something smaller.
            if (VirtualMode &&
                View == View.Details &&
                TopItem != null &&
                value > 0 &&
                TopItem.Index > value - 1)
            {
                TopItem = Items[value - 1];
            }

            base.VirtualListSize = value;
        }
    }

我正在尝试设置 listview 的 topitem 属性,但是在虚拟模式下,项目被禁用。所以任何试图在虚拟模式下访问它的代码都会抛出一个无效操作异常。当我尝试逐行调试时不会发生异常。如果我评论 TopItem=Items[value-1] 行,它不会引发任何异常。

System.InvalidOperationException:在 VirtualMode 中,ListView RetrieveVirtualListItem 事件需要每个 ListView 列的列表视图 SubItem。 在 System.Windows.Forms.ListView.WmReflectNotify(消息和 m) 在 System.Windows.Forms.ListView.WndProc(消息和 m) 在 System.Windows.Forms.NativeWindow.Callback(IntPtr hWnd,Int32 msg,IntPtr wparam,IntPtr lparam) 请建议。

【问题讨论】:

    标签: listview c#-3.0 listviewitem virtualmode


    【解决方案1】:

    当虚拟列表大小变小时,您无需更改TopItem。 .NET ListView 已经这样做了。根据 dotPeek 反汇编程序:

    public int VirtualListSize { 
        ... 
        set {
            ...
            bool keepTopItem = this.IsHandleCreated && VirtualMode && this.View == View.Details && !this.DesignMode; 
            int topIndex = -1;
            if (keepTopItem) { 
                topIndex = unchecked( (int) (long)SendMessage(NativeMethods.LVM_GETTOPINDEX, 0, 0)); 
            }
    
            virtualListSize = value;
    
            if (IsHandleCreated && VirtualMode && !DesignMode)
                SendMessage(NativeMethods.LVM_SETITEMCOUNT, virtualListSize, 0); 
    
            if (keepTopItem) { 
                topIndex = Math.Min(topIndex, this.VirtualListSize - 1); 
                // After setting the virtual list size ComCtl makes the first item the top item.
                // So we set the top item only if it wasn't the first item to begin with. 
                if (topIndex > 0) {
                    ListViewItem lvItem = this.Items[topIndex];
                    this.TopItem = lvItem;
                } 
            }
        } 
    }
    

    这个问题在于,根据我的经验,在虚拟列表视图上设置TopItem 是一个容易出错的活动。在我的代码中,我有这个块:

    // Damn this is a pain! There are cases where this can also throw exceptions!
    try {
        this.listview.TopItem = lvi;
    }
    catch (Exception) {
        // Ignore any failures
    }
    

    由于设置TopItem 有时会引发异常,这意味着有时设置VirtualListSize 同样会引发异常。

    其他要点

    可以通过索引访问Items集合,即使在虚拟模式下也是如此。所以,这很好(假设列表不为空):

    this.listview1.TopItem = this.listview1.Items[this.listview1.Items.Count - 1];
    

    不能在虚拟模式下迭代 Items 集合。这将引发异常:

    foreach (ListViewItem item in this.listview1.Items) { ... }
    

    【讨论】:

    • 好像我的代码没问题 TopItem = Items[value - 1]; .但它仍然抛出异常,我无法捕捉到异常。我找不到它是从哪里来的。但是,当我评论此行TopItem = Items[value - 1]; 时,它工作正常。但是,如果我逐行调试代码,它不会抛出任何异常。 System.InvalidOperationException:在 VirtualMode 中,ListView RetrieveVirtualListItem 事件需要每个 ListView 列的列表视图 SubItem。
    • 当您的 RetrieveVirtualListItem 处理程序返回不完整的 ListViewItem 时会引发该异常。我猜你的处理程序有一个逻辑错误。
    • 感谢您的帮助,我会检查处理程序的逻辑
    • 我有一个问题,为什么当我删除行 TopItem = Items[value - 1] 时没有引发异常??
    • 由于您的列表视图是虚拟的,代码Items[value - 1] 会导致RetrieveVirtualListItem 被触发。去掉那条线,就不会引发事件。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多