处于虚拟模式的.NET listview 中SelectAll
的正确/管理方式是什么?
启用ListView的VirtualMode
后,选择ListViewItem
的概念就会消失。您选择的唯一内容是索引。这些可以通过SelectedIndices
属性访问。
第一个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)。鉴于列表视图处于虚拟模式,期望列表中存在相当多的项目并非没有道理。
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。
无需借助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();
SelectAll
items of a non-virtual ListView