WinForms ListView和TreeView:奇怪的性能问题

时间:2012-02-07 08:34:56

标签: .net winforms performance listview treeview

在我们的项目中优化用户界面时,我发现ListView中有很多奇怪的提升,并且不明白它来自哪里。

简单地向listView添加5000个元素(视图:列表) - 3815毫秒:

for (int i = 0; i < 5000; i++)
         listView1.Items.Add((Guid.NewGuid().ToString()));

使用BeginUpdate()+ EndUpdate() - 2317 ms:

listView1.BeginUpdate();
for (int i = 0; i < 5000; i++)
    listView1.Items.Add((Guid.NewGuid().ToString()));
listView1.EndUpdate();

使用Hide()+ Show() - 163ms(没有错误,快10倍以上):

listView1.Hide();
for (int i = 0; i < 5000; i++)
    listView1.Items.Add((Guid.NewGuid().ToString()));
listView1.Show();

风格也发生了变化。 现在不是2列,而是4列。

为什么这种方式如此之快? 此外,为什么从隐藏的ListView(可见:false)开始,并在人口没有相同的性能提升后显示它?

TreeView是不同的。简单地添加5000个节点 - 2130毫秒:

for (int i = 0; i < 5000; i++)
    treeView1.Nodes.Add((Guid.NewGuid().ToString()));

使用Hide()+ Show() - 1048 ms:

treeView1.Hide();
for (int i = 0; i < 5000; i++)
    treeView1.Nodes.Add((Guid.NewGuid().ToString()));
treeView1.Show();

使用BeginUpdate()+ EndUpdate() - 291 ms:

treeView1.BeginUpdate();
for (int i = 0; i < 5000; i++)
    treeView1.Nodes.Add((Guid.NewGuid().ToString()));
treeView1.EndUpdate();

2 个答案:

答案 0 :(得分:2)

这似乎是一个错误。当控件被隐藏时,它不会计算项目的范围(类似Graphics.MeasureString或其本机等价物),当它们被添加时(这是有意义的)并且在以后控制时不计算它显示(这可能是一个错误)。因此,您可以获得4列而不是2列。请注意,当您获得2列时,项目不会被截断,因为执行了此大小计算。当你得到4列时,显示通常是不正确的。

为什么它从一开始就不会被隐形?原因是,因为在这种情况下,在您调用Show方法或创建强制创建句柄的任何内容之前,不会创建控件的句柄(尚未创建基础Win32控件)。然后,Show将首次创建句柄,执行许多其他代码,包括OnHandleCreated,此时代码会组织项目并计算其大小。

如果控件从头开始不可见,您可以检查IsHandleCreated属性是false,直到第一次Show来电。

您还可以显式创建句柄,即。通过简单地尝试读取Handle属性(这会强制创建句柄),然后它的行为方式相同 - 速度很快,但显示错误:

IntPtr handle = listView1.Handle;
for (int i = 0; i < 5000; i++)
    listView1.Items.Add((Guid.NewGuid().ToString()));
listView1.Show();

如果之前创建了句柄,则调用OnHandleCreated以及大小计算,但当时列表为空。

答案 1 :(得分:0)

因为如果你在没有隐藏列表视图的情况下添加元素..在元素之后绘制元素,当你隐藏listview时,它会一次绘制所有元素..