【问题标题】:WinForms TreeView.BeginUpdate does not prevent scrollbar recalculationWinForms TreeView.BeginUpdate 不会阻止滚动条重新计算
【发布时间】:2020-09-20 10:15:46
【问题描述】:

我有一个带有垂直滚动条的 WinForms TreeView。有时我必须重置节点并再次填充树。我在 BeginUpdate/EndUpdate 调用过程中执行此操作。但是当我调用 Nodes.Clear() 时,滚动条被重新计算以考虑节点的清除,并且在填充节点并调用 EndUpdate 之后再次重新计算。这会产生难看的闪烁。

        treeView.BeginUpdate()
        treeView.Nodes.Clear()
        CreateNodes(treeView.Nodes)
        treeView.EndUpdate() 

我认为调用 BeginUpdate/EndUpdate 会阻止 TreeView 的所有重绘。那么问题是我的猜测是否错误,而事实并非如此,在这种情况下,解决方案应该是什么。

(我使用的是 Visual Basic,.NET 框架 4.6.1)

【问题讨论】:

  • 这就是野兽的工作方式,你无能为力。我不会提到 LockWindowUpdate()。这通常不称为“闪烁”,您可能会抱怨 EndUpdate() 之后发生的重绘。将数百个节点填充到树中并不是一个好主意。也许双缓冲可以提供帮助,stackoverflow.com/a/10364283/17034
  • + 请注意,如果您有超过 200 个节点,treeView.Nodes.Clear() 已经在所有者 TreeView 上调用了 BeginUpdate() / EndUpdate(),因此您可能会调用它两次。 EndUpdate() 发送WM_SETREDRAW 然后Invalidate()。你需要有很多节点才能看到这个效果。 + CreateNodes() 在做什么是未定义的。
  • SendMessage(Parent.Handle, WM_SETREDRAW, False, 0) 正是BeginUpdate() 正在做的事情。在这种情况下,您可以防止重绘父对象。您的DrawItem 程序缺少对引发事件时发生的情况的检查。这并不是什么新鲜事,它取决于 TreeView 绘制其项目的方式:您可能会多次收到同一项目的相同事件,也许,您忘记检查项目是什么或当时的节点状态。所以你在不应该画的时候画它。即使您知道发生了什么,该代码也需要大量调试。
  • 你可以注意到,当你看到节点闪烁时,所有者绘制过程并不完美,即使你有非常几个项目。如果您单击一个节点并且您看到一个小的 运动 或感知到一个小的延迟,那么您的过程是不正确的:您正在绘制更多您应该绘制的内容。这很常见。

标签: c# .net vb.net winforms


【解决方案1】:

一个技巧帮助了我。它看起来像这样:

    BeginUpdate();
    Nodes.Add("...");
    Nodes[^1].Collapse(); //Important.
    for(...)
        Nodes[^1].Nodes.Add(...); //Adding nodes to a collapsed node create no lags.
    ExpandAll(); //Important.
    EndUpdate();

通过折叠刚刚添加的根节点,我的性能提高了 20 倍。 顺便说一句,我有两棵相同形式的树。第一个中的 BeginUpdate 完美运行,而第二个中的 BeginUpdate 什么也不做。我不知道为什么。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2010-09-30
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-11-03
    • 2020-07-06
    • 2014-11-02
    相关资源
    最近更新 更多