【问题标题】:How do I select all items in a listbox on checkbox checked?如何在选中复选框时选择列表框中的所有项目?
【发布时间】:2010-10-30 08:57:17
【问题描述】:

单击 CheckBox 时,我需要选择 ListBox 中的所有项目。是否可以使用一行代码选择 ListBox 中的所有项目?还是我必须遍历所有项目并将每个项目的 selected 设置为 true?

【问题讨论】:

    标签: c# winforms listbox .net-2.0


    【解决方案1】:

    事实上ListBox.Items是一个普通的对象集合,返回普通的无类型对象,不能多选(默认)。

    如果您想多选所有项目,那么这将起作用:

       for (int i = 0; i < myListBox.Items.Count;i++)
       {
           myListBox.SetSelected(i, true);
       }
    

    【讨论】:

    • 假设此逻辑与在 KeyDown 事件中处理的组合键(例如 Ctrl+A)相关联,您还需要确保包含 e.SuppressKeyPress = true;否则它会将您的选择恢复为列表中的第一个“A”。
    • 对于大型列表,应该暂停更新。 stackoverflow.com/q/15398091/340790
    【解决方案2】:

    我已经看到了许多(类似的)答案,它们在逻辑上都做同样的事情,我很困惑为什么它们都不适合我。关键是将列表框的SelectionMode 设置为SelectionMode.MultiSimple。它不适用于SelectionMode.MultiExtended。考虑在列表框中选择多个项目,您将选择模式设置为多个模式,并且大多数人会选择传统的MultiExtended 样式,这个答案应该会有很大帮助。而且你不是foreach,而是for

    你实际上应该这样做:

    lb.SelectionMode = SelectionMode.MultiSimple;
    for (int i = 0; i < lb.Items.Count; i++)
        lb.SetSelected(i, true);
    lb.SelectionMode = //back to what you want
    

    lb.SelectionMode = SelectionMode.MultiSimple;
    for (int i = 0; i < lb.Items.Count; i++)
        lb.SelectedIndices.Add(i);
    lb.SelectionMode = //back to what you want
    

    【讨论】:

    • 如果你添加e.SuppressKeyPress = true;它应该可以工作,不管SelectionMode。
    【解决方案3】:

    据我所知,使用任何 .NET 方法选择大量项目都比直接调用 PInvoke 慢得多,将 LB_SETSEL 消息 (0x185) 传递给控件,​​并带有一个标志指示是否您想要选择 (1) 或取消选择 (0) 以及表示更改应应用于所有项目的魔法值 (-1)。

      [DllImport("user32.dll", EntryPoint = "SendMessage")]
      internal static extern IntPtr SendMessage(IntPtr hWnd, UInt32 msg, IntPtr wParam, IntPtr lParam);
    
      // Select All
      SendMessage(listBox.Handle, 0x185, (IntPtr)1, (IntPtr)(-1));
    
      // Unselect All
      SendMessage(listBox.Handle, 0x185, (IntPtr)0, (IntPtr)(-1));
    

    【讨论】:

    • 不错的尝试。它确实选择了所有项目,但项目枚举失败。问题是,在 SendMessage 选择所有项目后,我得到 SelectedItems.Count 显示所有列表框项目的计数(这是正确的)。但是当我试图枚举 SelectedItems 时 - 只执行一次迭代。当我执行SelectedItems[SelectedItems.Count - 1] IndexOutOfRange 时抛出异常。似乎选择了项目,但列表框不会用它们刷新内部列表。要计算SelectedObjectCollection.Count 属性,getter 发送另一个窗口消息,返回所有项目的计数。
    • -1 并不是那么神奇,请参阅LB_SETSEL message (Windows)。顺便说一句:它适用于 VCL 类 TListBox。
    • 嗨,@Wolf。 “魔术”一词在编程中具有特殊的含义。见en.wikipedia.org/wiki/Magic_number_(programming)
    • 是的,我知道。但有时 magic 也指可以更好地被符号常量替换的整数文字,而某些文字是首选的,例如 0。-1 对于基于 0 的索引的“例外”情况很突出,其中0(又名 NULL)不适合。
    • @Wolf:我没有遇到任何问题(我在 Fiddler 中使用了这种技术)。话虽如此,在执行选择后只允许发送消息(例如,通过调用 Application.DoEvents)可能可以解决此问题。
    【解决方案4】:

    我认为你必须在这里循环。一次选择所有项目是一个非常具体(并且可能很少见)的用例,开箱即用地提供该功能毫无意义。此外,无论如何,循环只是两行代码。

    【讨论】:

      【解决方案5】:

      我使用 Mika 的解决方案,但是如果您有数千个项目,这可能会非常慢。要大幅提高速度,您可以暂时关闭可见性。列表框在操作过程中实际上不会像您可能怀疑的那样消失,但在我的情况下,选择的速度至少快了 10 倍。

      myListBox.Visible = false;
      for (int i = 0; i < myListBox.Items.Count;i++)
      {
          myListBox.SetSelected(i, true);
      }
      myListBox.Visible = true;
      

      【讨论】:

      • 我相信myListBox.Visible = false 更快,因为它避免了在更新时绘制。我会使用myListBox.BeginUpdate()myListBox.EndUpdate() 提供的方法 :)
      • +1 评论 DiogoNeves。更好,因为它也会使焦点停留在列表框上。对于 Robin 的解决方案,必须在再次将其设置为可见后调用 myListBox.Focus()。
      【解决方案6】:

      在此构造函数中,您需要启用所需文本框的多选模式(MultiExtended)。

      public Form1()
      {
          InitializeComponent();
          listBox1.SelectionMode = SelectionMode.MultiExtended;
          listBox2.SelectionMode = SelectionMode.MultiExtended;
      }
      

      在此之后,使用循环选择所有内容:

      private void selectAll_Click(object sender, EventArgs e)
      {
          for (int val = 0; val < listBox1.Items.Count; val++)
          {
              listBox1.SetSelected(val, true);
          }
      }
      

      我测试过了。有用。您也可以使用 [CTRL/SHIFT] 按钮 + 左键单击单独选择项目。

      【讨论】:

        【解决方案7】:

        在我的情况下,我有 10k+ 个项目,基本循环方法需要将近一分钟才能完成。使用@DiogoNeves 回答并扩展它,我希望能够全选(Ctrl+A)和复制(Ctrl+C)。我处理了这两种方式。我使用 BeginUpdate() 和 EndUpdate() 来推迟绘图,但我还添加了一个直接复制所有 (Ctrl+Shift+C),它甚至不需要在复制之前选择项目。

        private static void HandleListBoxKeyEvents(object sender, KeyEventArgs e)
        {
            var lb = sender as ListBox;
            // if copy
            if (e.Control && e.KeyCode == Keys.C)
            {
                // if shift is also down, copy everything!
                var itemstocopy = e.Shift ? lb.Items.Cast<object>() : lb.SelectedItems.Cast<object>();
                // build clipboard buffer
                var copy_buffer = new StringBuilder();
                foreach (object item in itemstocopy)
                    copy_buffer.AppendLine(item?.ToString());
                if (copy_buffer.Length > 0)
                    Clipboard.SetText(copy_buffer.ToString());
            }
            // if select all
            else if (e.Control && e.KeyCode == Keys.A)
            {
                lb.BeginUpdate();
                for (var i = 0; i < lb.Items.Count; i++)
                    lb.SetSelected(i, true);
                lb.EndUpdate();
            }
        }
        

        【讨论】:

          【解决方案8】:

          如果你有很多(100+)项,这绝对不是很好,但比循环快得多: 选择Listbox,模拟[home]和[shift]+[end]的按键输入

          lb.BeginUpdate();
          lb.Select();
          SendKeys.Send("{Home}");
          SendKeys.Send("+{End}");
          lb.EndUpdate();
          

          编辑:我猜只适用于 SelectionMode.MultiExtended

          DoubleEDit:还请注意,这对于之后使用 lb.selecteditems 执行的代码可能太慢,但对于用户将单击的 [全选] 按钮可能很有用。

          【讨论】:

          • 对我不起作用(使用 .Net 4.7)。列表框只是闪烁,仅此而已。
          【解决方案9】:

          全选绝对是开箱即用的:

          $("#ListBoxID option").prop("selected", true);
          

          【讨论】:

          • 这个问题是针对winforms而不是web
          • 此代码也不是开箱即用的。列出的代码是 jQuery 而不是 C#/VB.NET
          • 答案是问题的适当解决方案!
          【解决方案10】:

          我知道这个问题是用 .NET 2.0 标记的,但是如果您在 3.5+ 中可以使用 LINQ,则可以执行以下操作:

          ASP.NET 网络表单

          var selected = listBox.Items.Cast<System.Web.UI.WebControls.ListItem>().All(i => i.Selected = true);
          

          WinForms

          var selected = listBox.SelectedItems.Cast<int>().ToArray();
          

          【讨论】:

          • 不 - 我得到 找不到类型或名称 ListItem。 (您是否缺少 Using 指令或程序集引用)。
          • 对解决方案投反对票似乎有点过分,而不是与人一起找出解决方案可能不适合您的原因。您是否有提到的缺少使用指令using System.Web.UI.WebControls;?您是否引用程序集?已更新答案以引用程序集。
          • 对不起 fujiface - 我又给你投票了。我最初以为你是在 2014 年写的,所以我没想到会有回应。我似乎无法访问 System.Web.UI.WebControls。我只能看到 System.Web。我试图添加对它的引用,但它也没有出现在那里。也许它在 4.7 中已被弃用?我查找了具有该名称的 NuGet 包,但也不存在。
          • 查看 MSDN 上的文档,我看到了 System.Web.UI.Design.WebControls 命名空间,但我似乎无法在我的代码中访问它。
          • 没问题@Ben_G。那是个很好的观点。根据您拥有的项目类型(我的项目是基于 Web 的,并且 OP 大约在 2009 年使用 WinForms),您可能无法访问服务器控件。我并没有真正指定 ListItem 类型,因为问题被标记为 WinForms 并且仔细查看我的答案,它可能需要进一步调整以在 WinForms 上下文中。
          【解决方案11】:

          我将nawfal 的想法添加到我已有的想法中,这也是'BeginUpdate'。另外,正如用户所期望的那样,视图位置也得到了维护。对我来说,这似乎解决了所有问题:

          public void SelectAll()
          {
              bool prevBusy = MouseHelper.IsBusy;
              MouseHelper.IsBusy = true;
              int topIndex = TopIndex;
          
              // BUG: In 'SelectionMode.MultiExtended' the box gets crazy
              SelectionMode previousMode = this.SelectionMode;
              this.SelectionMode = SelectionMode.MultiSimple;
          
              this.BeginUpdate();
          
              for (int i = 0; i < Items.Count; i++)
              {
                  SelectedIndices.Add(i);
              }
          
              this.EndUpdate();
              this.SelectionMode = previousMode;
          
              TopIndex = topIndex;
              MouseHelper.IsBusy = prevBusy;
          }
          

          【讨论】:

            【解决方案12】:
            private void Button_Click(object sender, RoutedEventArgs e)
                {
            
                        listbox.SelectAll();
            
                }
            

            【讨论】:

            • 这是哪个版本的 .Net?
            • WinForms ListBox 中没有 SelectAll 方法。您可能正在考虑 WPF ListBox,但这个问题被标记为“winforms”和“.net-2.0”。
            猜你喜欢
            • 2014-09-01
            • 2019-11-24
            • 1970-01-01
            • 1970-01-01
            • 2017-05-05
            • 1970-01-01
            • 1970-01-01
            • 2013-01-23
            • 2011-09-25
            相关资源
            最近更新 更多