winforms 在大型ListView上枚举ListView.SelectedIndices的速度很慢

6l7fqoea  于 2023-04-21  发布在  其他
关注(0)|答案(4)|浏览(136)

我有一个VirtualMode = true的ListView和大量的项目(现在~ 800,000)。
我的目标是每次选定项发生变化时,对所有选定项中的字段求和。
问题是,当选择大量项目时,枚举所有选中的项目需要很长时间。例如,枚举800,000个选中的项目需要1秒。这意味着对于每个单一的选择更改,用户必须等待1秒才能再次响应GUI,这很烦人。
我不明白为什么枚举选中的项如此缓慢,在一个简单的数组中枚举相同数量的项什么也不需要。
如何加快列表视图中所选项目的枚举过程?

58wvjzkj

58wvjzkj1#

WinForms ListView的一个问题是,它是建立在Win32Control之上的,因此对ListView的每个请求都必须从托管代码传递到无人代码,然后再传递回来。

var myArray = new int[myListView.SelectedIndices.Count];
myListView.SelectedIndices.CopyTo(myArray)

可能会快一些,值得一试
否则,您是否考虑过使用WPF?您可以为列表编写单个WPF控件,然后将其托管在WinForm窗体中。

sshcrbum

sshcrbum2#

这取决于你是如何做的,你可能想用一些代码来详细说明,但是你不能在选择每个项目时保持一个运行的总数,而不是每次选择时都要遍历整个列表吗?

mkshixfv

mkshixfv3#

底层控件是主要问题,它只是需要一定的时间来检查每一项,并决定它是否是下一个选中的行。
通过直接向控件发送消息,可以使枚举过程的速度提高一倍左右:

[DllImport("user32.dll")]
public static extern int SendMessage(IntPtr hWnd, int msg, int wParam, int lParam);

private void button1_Click(object sender, EventArgs e)
{
    Stopwatch sw = new Stopwatch();

    sw.Start();
    IntPtr h = this.listView1.Handle;
    int j = 0;
    int i = SendMessage(h, 0x100C, -1, 2);
    while (i > -1) {
        j++;
        i = SendMessage(h, 0x100C, i, 2);
    }

    sw.Stop();
    this.toolStripStatusLabel1.Text = String.Format("Timed: {0} items in {1}ms",
        j, sw.ElapsedMilliseconds);
}

在我的机器上,这将迭代所选项目所需的时间减半,但这个过程永远不会是即时的。

vbopmzt1

vbopmzt14#

在我的具体情况下,性能得到了很大的改善,从

for (int selectionIndex = 0; selectionIndex < listObj.SelectedIndices.Count; selectionIndex++)
    {
        int realIndex = listObj.SelectedIndices[selectionIndex];
        ListViewItem lviItem = listObj.Items[realIndex];
        
        // Your actions on selected element...
    }

for (int realIndex = 0; realIndex < listObj.Items.Count; realIndex++)
{
    ListViewItem lviItem = listObj.Items[realIndex];
    if(!lviItem.Selected)
        continue;
    
    // Your actions on selected element...
}

希望这能帮助到别人。

相关问题