使用 WinAPI 设置 ListViewItem 的选中状态

Gru*_*ola 2 c# winapi listview

我尝试使用以下代码来检查和取消选中列表视图中的项目。在一切的背后,检查功能似乎正在发挥作用。问题是取消选中功能不起作用,并且选中已选中的项目只会使复选框可见,而不会触发选中事件或取消选中该框。我发现的所有内容都表明这应该可行,但我只是无法在这里提出可行的解决方案。谁能解释为什么 0x1000 没有取消选中这些项目以及为什么复选框对我来说不可见?

谢谢

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

    private const int LVIF_STATE = 0x8;

    private const int LVIS_UNCHECKED = 0x1000;
    private const int LVIS_CHECKED = 0x2000;
    private const int LVIS_CHECKEDMASK = 0x3000;

    [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(IntPtr hWnd, int msg, int wParam, ref LVITEM lvi);

    /// <summary>
    /// Check all rows on the given listview
    /// </summary>
    /// <param name="list">The listview whose items are to be checked</param>
    public static void CheckAllItems(ListView list)
    { // -1 index means all items in the list
      SetItemState(list, -1, LVIS_CHECKED, LVIS_CHECKEDMASK);
    }

    /// <summary>
    /// Uncheck all rows on the given listview
    /// </summary>
    /// <param name="list">The listview whose items are to be unchecked</param>
    public static void UncheckAllItems(ListView list)
    { // -1 index means all items in the list
      SetItemState(list, -1, LVIS_UNCHECKED, LVIS_CHECKEDMASK);
    }

    /// <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 list, int itemIndex, int mask, int value)
    {
      LVITEM lvItem = new LVITEM();
      lvItem.mask = LVIF_STATE;
      lvItem.stateMask = mask;
      lvItem.state = value;
      SendMessageLVItem(list.Handle, LVM_SETITEMSTATE, itemIndex, ref lvItem);
    }
  }
Run Code Online (Sandbox Code Playgroud)

编辑

我在这里双重检查了行为,当我为未选中的项目选择“全部选中”并为选中的项目选择“全部取消选中”时,就会发生这种情况。他们变得不可见。“取消全部选中”不会将项目从选中状态更改为未选中状态,但这显然是正确的状态,因为在没有选中任何项目的情况下选择“取消全选”不会导致任何更改。当所有项目都已选中时,“全选”也是如此。

Gru*_*ola 5

我在这里为我的错误道歉。我交换了掩码和值,所以这是正确的解决方案:

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

  private const int LVIS_UNCHECKED = 0x1000;
  private const int LVIS_CHECKED = 0x2000;
  private const int LVIS_STATEIMAGEMASK = 0x3000;

  [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(IntPtr hWnd, int msg, int wParam, ref LVITEM lvi);

  /// <summary>
  /// Select all rows on the given listview
  /// </summary>
  /// <param name="list">The listview whose items are to be selected</param>
  public static void CheckAllItems(ListView list)
  {
    SetItemState(list, -1, LVIS_STATEIMAGEMASK, LVIS_CHECKED);
  }

  /// <summary>
  /// Deselect all rows on the given listview
  /// </summary>
  /// <param name="list">The listview whose items are to be deselected</param>
  public static void UncheckAllItems(ListView list)
  {
    SetItemState(list, -1, LVIS_STATEIMAGEMASK, LVIS_UNCHECKED);
  }

  /// <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 list, int itemIndex, int mask, int value)
  {
    LVITEM lvItem = new LVITEM();
    lvItem.stateMask = mask;
    lvItem.state = value;
    SendMessageLVItem(list.Handle, LVM_SETITEMSTATE, itemIndex, ref lvItem);
  }
}
Run Code Online (Sandbox Code Playgroud)