【发布时间】:2010-10-30 08:57:17
【问题描述】:
单击 CheckBox 时,我需要选择 ListBox 中的所有项目。是否可以使用一行代码选择 ListBox 中的所有项目?还是我必须遍历所有项目并将每个项目的 selected 设置为 true?
【问题讨论】:
标签: c# winforms listbox .net-2.0
单击 CheckBox 时,我需要选择 ListBox 中的所有项目。是否可以使用一行代码选择 ListBox 中的所有项目?还是我必须遍历所有项目并将每个项目的 selected 设置为 true?
【问题讨论】:
标签: c# winforms listbox .net-2.0
事实上ListBox.Items是一个普通的对象集合,返回普通的无类型对象,不能多选(默认)。
如果您想多选所有项目,那么这将起作用:
for (int i = 0; i < myListBox.Items.Count;i++)
{
myListBox.SetSelected(i, true);
}
【讨论】:
我已经看到了许多(类似的)答案,它们在逻辑上都做同样的事情,我很困惑为什么它们都不适合我。关键是将列表框的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。
据我所知,使用任何 .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));
【讨论】:
SelectedItems[SelectedItems.Count - 1] IndexOutOfRange 时抛出异常。似乎选择了项目,但列表框不会用它们刷新内部列表。要计算SelectedObjectCollection.Count 属性,getter 发送另一个窗口消息,返回所有项目的计数。
Application.DoEvents)可能可以解决此问题。
我认为你必须在这里循环。一次选择所有项目是一个非常具体(并且可能很少见)的用例,开箱即用地提供该功能毫无意义。此外,无论如何,循环只是两行代码。
【讨论】:
我使用 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() 提供的方法 :)
在此构造函数中,您需要启用所需文本框的多选模式(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] 按钮 + 左键单击单独选择项目。
【讨论】:
在我的情况下,我有 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();
}
}
【讨论】:
如果你有很多(100+)项,这绝对不是很好,但比循环快得多: 选择Listbox,模拟[home]和[shift]+[end]的按键输入
lb.BeginUpdate();
lb.Select();
SendKeys.Send("{Home}");
SendKeys.Send("+{End}");
lb.EndUpdate();
编辑:我猜只适用于 SelectionMode.MultiExtended
DoubleEDit:还请注意,这对于之后使用 lb.selecteditems 执行的代码可能太慢,但对于用户将单击的 [全选] 按钮可能很有用。
【讨论】:
全选绝对是开箱即用的:
$("#ListBoxID option").prop("selected", true);
【讨论】:
我知道这个问题是用 .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();
【讨论】:
using System.Web.UI.WebControls;?您是否引用程序集?已更新答案以引用程序集。
我将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;
}
【讨论】:
private void Button_Click(object sender, RoutedEventArgs e)
{
listbox.SelectAll();
}
【讨论】: