如何在选中复选框时选择列表框中的所有项目?

Posted

技术标签:

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

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

【问题讨论】:

【参考方案1】:

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

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

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

【讨论】:

假设此逻辑与在 KeyDown 事件中处理的组合键(例如 Ctrl+A)相关联,您还需要确保包含 e.SuppressKeyPress = true;否则它会将您的选择恢复为列表中的第一个“A”。 对于大型列表,应该暂停更新。 ***.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”。

以上是关于如何在选中复选框时选择列表框中的所有项目?的主要内容,如果未能解决你的问题,请参考以下文章

选择/取消选择所有复选框 WIN32

当一个或多个项目被取消选择时,knockoutjs 取消选择/选择所有复选框

mfc如何将复选框勾选后,把里面内容实时传到列表框中?

如何禁用多选框中的其余所有项目

列表视图Item.Selected = false导致未选中所有复选框

如何使用uwp中的全选复选框创建带有复选框项目的列表视图