【问题标题】:how do I make a WinForms ListBox who's items toggle on and off我如何制作一个 WinForms ListBox 谁的项目打开和关闭
【发布时间】:2011-04-23 04:02:57
【问题描述】:

我所追求的功能是复选列表框和多选模式下的列表框之间的交叉。

对于列表框项目 A 和 B

  • A 然后 B 会导致从 A 移动到 B 的单个选择。

  • A 然后按住 Control 键单击 B 会导致 A 和 B 的多选。

(我想要的是):

  • A then A 导致 A 切换打开和关闭。

我认为这很容易,但我想不通。也许我遗漏了一些明显的东西,或者我想错了,没有人真正想要一个列表框,其中的项目可以打开/关闭。

【问题讨论】:

  • 标题很清楚,但你的问题确实不是。您是否只是要求带有SelectionMode.One 的列表框与SelectionMode.MultiSimpleSelectionMode.MultiExtented 类似地切换?我将添加此问题的答案,但请改写问题。

标签: c# winforms listbox


【解决方案1】:

如果您将 SelectionMode 设置为 MultiSimple,则您可以通过控制单击进行多选以及打开和关闭切换。

要使移动选择起作用,您可以处理 SelectedIndexChanged 事件并添加一些逻辑以在未按下控件时取消选择其他项目。如果以后有更多时间,我可以尝试为它创建一些基本代码,但这应该是开始的地方。

【讨论】:

    【解决方案2】:

    如果您将 ListBox.SelectionMode 设置为 MultiExtended 并在进行选择时按住控件,则您已经拥有所需的行为。

    【讨论】:

      【解决方案3】:

      如果我正确理解了您的问题,您需要一个带有SelectionMode.OneListBox,它可以使用CTLR 修饰符切换选择,类似于SelectionMode.MultiSimpleSelectionMode.MultiExtented。在我的回答下方,只需将 ToggleSingleSelection 设置为 true。此外,它还提供了在单击已选择项目时也会触发的项目单击事件。

      using System;
      using System.Drawing;
      using System.Windows.Forms;
      
      namespace Common
      {
          public class ListBoxEx : ListBox
          {
              public event ItemClickedEventHandler ItemClick;
              public event ItemClickedEventHandler ItemDoubleClick;
      
              /// <summary>
              /// Toggle selections when list has SelectionMode.One
              /// </summary>
              public bool ToggleSingleSelection { get; set; }
      
              int _PreSelectedIndex = -1;
              int _PrevClickedItem = -1;
      
              protected override void OnSelectedIndexChanged(EventArgs e)
              {
                  base.OnSelectedIndexChanged(e);
              }
      
              protected override void WndProc(ref Message m)
              {
                  const int WM_LBUTTONDOWN = 0x201;
                  switch (m.Msg)
                  {
                      case WM_LBUTTONDOWN:
                          // NOTE: Unfortunately SelectedIndex is already setted before OnMouseDown,
                          // so we must intercept mouse click even before to compare
                          _PreSelectedIndex = SelectedIndex;
                          break;
                  }
      
                  base.WndProc(ref m);
              }
      
              protected override void OnMouseClick(MouseEventArgs e)
              {
                  base.OnMouseClick(e);
      
                  // Reset clicked event, also for double click
                  _PrevClickedItem = -1;
                  int selectedIndex = SelectedIndex;
                  if (selectedIndex != -1)
                  {
                      Rectangle selectedItemRectangle = GetItemRectangle(selectedIndex);
                      if (selectedItemRectangle.Contains(e.Location))
                      {
                          _PrevClickedItem = selectedIndex;
      
                          // Check when to toggle selection
                          if (SelectionMode == SelectionMode.One && ToggleSingleSelection && ModifierKeys.HasFlag(Keys.Control)
                              && _PreSelectedIndex != -1 && selectedIndex == _PreSelectedIndex)
                          {
                              SelectedIndex = -1;
                          }
      
                          if (_PrevClickedItem != -1)
                              OnItemClick(new ItemClickedEventArgs() { ItemIndex = _PrevClickedItem });
                      }
                  }
              }
      
              protected override void OnMouseDoubleClick(MouseEventArgs e)
              {
                  base.OnMouseDoubleClick(e);
      
                  if (_PrevClickedItem != -1)
                      OnItemDoubleClick(new ItemClickedEventArgs() { ItemIndex = _PrevClickedItem });
              }
      
              protected virtual void OnItemDoubleClick(ItemClickedEventArgs args)
              {
                  ItemDoubleClick?.Invoke(this, args);
              }
      
              protected virtual void OnItemClick(ItemClickedEventArgs args)
              {
                  ItemClick?.Invoke(this, args);
              }
          }
      
          public class ItemClickedEventArgs : EventArgs
          {
              public int ItemIndex { get; set; }
          }
      
          public delegate void ItemClickedEventHandler(Control sender, ItemClickedEventArgs args);
      }
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2010-12-13
        • 2017-08-07
        • 1970-01-01
        • 2016-05-26
        • 1970-01-01
        • 1970-01-01
        • 2017-11-23
        • 2011-08-22
        相关资源
        最近更新 更多