【问题标题】:WinForms ListView and TreeView: strange performance issuesWinForms ListView 和 TreeView:奇怪的性能问题
【发布时间】:2012-02-28 16:44:33
【问题描述】:

在我们的项目中优化 UI 时,我注意到 ListView 中的提升非常奇怪,但不明白它来自哪里。

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

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

使用 BeginUpdate() + EndUpdate() - 2317 毫秒:

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

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

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

风格也变了。 现在我有 4 列,而不是 2 列。

为什么这种方式这么快? 此外,为什么从隐藏的 ListView (Visible: false) 开始,在填充后显示它没有相同的性能提升?

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

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

使用 Hide() + Show() - 1048 毫秒:

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

使用 BeginUpdate() + EndUpdate() - 291 毫秒:

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

【问题讨论】:

  • 将您的项目添加到列表中,然后调用AddRange(...) 您也应该手动指定您的列,而不是信任控件来动态分配它们。

标签: .net winforms performance listview treeview


【解决方案1】:

这似乎是一个错误。当控件被隐藏时,它不会在添加项目时计算项目的范围(类似于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 连同大小计算也被调用,但当时列表为空。

【讨论】:

    【解决方案2】:

    因为如果你添加元素而不隐藏listview..是在一个元素之后绘制元素,当你隐藏listview时,它会一次绘制所有元素..

    【讨论】:

    • 真正的问题是:为什么从隐藏的 ListView (Visible: false) 开始,并在填充后显示它没有相同的性能提升?为什么隐藏/显示更改可见列数?
    • 相同的答案..因为,如果它是可见的,你添加的每个元素都是单独绘制的(它在每个新元素之后调用 - 绘制).. 但是如果你隐藏组件并在显示之后。 . 它全部绘制(添加所有元素,然后全部绘制在 gui 上)..
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多