如何快速选择 ListBox 中的所有项?

6

我在Windows Forms表单上有一个自绘的ListBox,绑定到数据源(BindingList)。我需要提供一种选择所有项目的选项(最多500000个),速度非常快。

这是我当前正在做的事情:

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

这太慢了,无法接受。有人知道更好的解决方案吗?

最好努力减少那些项目的数量。 - Steve
很久没有使用表单了。你能做类似于 listBox.SelectedItems = listBox.Items 这样的事情吗?对于 SelectedIndexes 呢? - Rob
3
离题了,但我不认为一个包含 500,000 个项目的列表框会很好用。您可能需要重新审查您的设计。 - Frédéric Hamidi
1
@Rob:不,SelectedItems是只读的。 - Norman
你在选择项目之前使用了BeginUpdate和EndUpdate吗? - Gusman
显示剩余6条评论
5个回答

9
假设这是一个与Windows窗体相关的问题:Windows窗体将在每个选定项目之后绘制更改。要禁用绘制并在完成后启用它,请使用BeginUpdate()EndUpdate()方法。
listBox.BeginUpdate();

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

listBox.EndUpdate();

完美!这样速度快多了。 - Norman
@Maertin 请看问题。 - Norman
@Norman,我已经在示例中添加了代码。最好不要在一个问题中重复解决方案。投票系统应该将最佳解决方案放在顶部。社区可能仍然认为另一个解决方案更好! - Myrtle
请注意 - 一定要检查与选择更改相关的任何事件。这显然会减慢速度。 - DAG

1

我找不到一种足够快速以至于可以被接受的方法。 我尝试了BeginUpdate/EndUpdate,虽然有所帮助,但在Intel Core i5笔记本电脑上仍需要4.3秒。 所以这很糟糕,但它能用 - 至少在IDE中是这样的。 ListBox被称为lbxItems,在表单上我有一个名为Select All的按钮。在该按钮的单击事件中,我有:

//save the current scroll position
int iTopIndex = lbxItems.TopIndex;

//select the [0] item (for my purposes this is the top item in the list)
lbxItems.SetSelected(0, true);

// put focus on the listbox
lbxItems.Focus();

//then send Shift/End (+ {END}) to SendKeys.SendWait
SendKeys.SendWait("+{END}");

// restore the view (scroll position)
lbxItems.TopIndex = iTopIndex;

结果:这可以在几毫秒内选择10,000个项目,就像我实际使用键盘一样。


奇怪的是,即使我已经禁用了粘滞键,如果我将这个放在一个KeyPress处理程序中以响应Ctrl-A,它仍然会间歇性地调用粘滞键。 - Tony Edgecombe

0

那是针对WPF的,不是Windows Forms。 - Tony Edgecombe

-1

@MauriceStam的建议结合这个可能是最好的解决方案(不确定SelectAll是否在内部禁用绘图)。 - Rob
1
这取决于他是否使用WPF或Windows Forms。WF没有SelectAll方法。 - Myrtle
1
那是针对WPF的。提问者正在使用Windows Forms(因为WPF没有SetSelected())。 - Frédéric Hamidi
是的,Windows Forms,抱歉 ;) - Norman
哦,好的抱歉。你可以这样做来使它稍微快一点。a = Listbox.Items.Count; 然后使用 a 进行循环。 - Maertin

-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或SelectedIndices。 - Tony Edgecombe
@TonyEdgecombe 从问题中可以看出,这不是一个要求。 - Norman

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接