如何在WinForms虚拟ListView中选择全部?

时间:2012-01-27 21:00:27

标签: winforms listview virtual

处于虚拟模式的.NET listview SelectAll的正确/管理方式是什么?

启用ListView的VirtualMode后,选择ListViewItem的概念就会消失。您选择的唯一内容是索引。这些可以通过SelectedIndices属性访问。

解决方法#1

第一个hack是迭代添加每个索引到SelectedIncides集合:

this.BeginUpdate();
try
{
    for (int i = 0; i < this.VirtualListSize; i++)
        this.SelectedIndices.Add(i);
}
finally     
{
    this.EndUpdate();
}

除了设计不佳(繁忙的循环计数到十万)之外,它表现不佳(it throws an OnSelectedIndexChanged event every iteration)。鉴于列表视图处于虚拟模式,期望列表中存在相当多的项目并非没有道理。

解决方法#2

Windows ListView控件完全能够一次选择所有项目。向列表视图发送LVM_SETITEMSTATE消息,告诉它“选择”所有项目。:

LVITEM lvi;
lvi.stateMask = 2; //only bit 2 (LVIS_SELECTED) is valid
lvi.state = 2;     //setting bit two on (i.e. selected)

SendMessage(listview.Handle, LVM_SETITEMSTATE, -1, lvi); //-1 = apply to all items

这很好用。它会立即发生,最多只会引发两个事件:

class NativeMethods
{
    private const int LVM_SETITEMSTATE = LVM_FIRST + 43;

    [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
    public struct LVITEM
    {
        public int mask;
        public int iItem;
        public int iSubItem;
        public int state;
        public int stateMask;
        [MarshalAs(UnmanagedType.LPTStr)]public string pszText;
        public int cchTextMax;
        public int iImage;
        public IntPtr lParam;
        public int iIndent;
        public int iGroupId;
        public int cColumns;
        public IntPtr puColumns;
    };

    [DllImport("user32.dll", EntryPoint = "SendMessage", CharSet = CharSet.Auto)]
    public static extern IntPtr SendMessageLVItem(HandleRef hWnd, int msg, int wParam, ref LVITEM lvi);

    /// <summary>
    /// Select all rows on the given listview
    /// </summary>
    /// <param name="listView">The listview whose items are to be selected</param>
    public static void SelectAllItems(ListView listView)
    {
        NativeMethods.SetItemState(listView, -1, 2, 2);
    }

    /// <summary>
    /// Set the item state on the given item
    /// </summary>
    /// <param name="list">The listview whose item's state is to be changed</param>
    /// <param name="itemIndex">The index of the item to be changed</param>
    /// <param name="mask">Which bits of the value are to be set?</param>
    /// <param name="value">The value to be set</param>
    public static void SetItemState(ListView listView, int itemIndex, int mask, int value)
    {
        LVITEM lvItem = new LVITEM();
        lvItem.stateMask = mask;
        lvItem.state = value;
        SendMessageLVItem(new HandleRef(listView, listView.Handle), LVM_SETITEMSTATE, itemIndex, ref lvItem);
    }
}

但它依赖于P / Invoke互操作。它还依赖于.NET ListView是Windows ListView控件的包装器的事实。这并非总是如此。

所以我希望正确的,托管的方式SelectAll是一个.NET WinForms ListView。

Bonus Chatter

无需借助P / Invoke来取消选择列表视图中的所有项目:

LVITEM lvi;
lvi.stateMask = 2; //only bit 2 (LVIS_SELECTED) is valid
lvi.state = 1;     //setting bit two off (i.e. unselected)

SendMessage(listview.Handle, LVM_SETITEMSTATE, -1, lvi); //-1 = apply to all items

托管等价物同样快:

listView.SelectedIndices.Clear();

奖金阅读

0 个答案:

没有答案