【问题标题】:Treeview flickering?树状图闪烁?
【发布时间】:2012-04-28 11:16:45
【问题描述】:

我知道通过添加 TreeView.BeginUpdate 将防止树视图闪烁,但是当我将它添加到我的项目中时,我的树视图的所有节点都消失了,任何人都可以告诉我为什么会发生,这里是代码 sn- p 我使用 TreeView.BeginUpdate 和 TreeView.EndUpdate 的地方

  TreeNode treeNode = new TreeNode("Windows");
        treeView1.Nodes.Add(treeNode);
        //
        // Another node following the first node.
        //
        treeNode = new TreeNode("Linux");
        treeView1.Nodes.Add(treeNode);
        //
        // Create two child nodes and put them in an array.
        // ... Add the third node, and specify these as its children.
        //
        TreeNode node2 = new TreeNode("C#");
        TreeNode node3 = new TreeNode("VB.NET");
        TreeNode[] array = new TreeNode[] { node2, node3 };
        //
        // Final node.
        //
        treeNode = new TreeNode("Dot Net Perls", array);
        treeView1.Nodes.Add(treeNode);

【问题讨论】:

  • 第一个看起来不正确 - 你在循环中执行 BeginUpdate/EndUpdate - 更糟糕的是,EndUpdate 嵌套在一些条件代码中 - 我通常会这样做期望看到一些抑制视觉更新的东西被包裹在整个更新集中(根据你的第二个例子)
  • 尽管代码有问题,但您似乎正在尝试解决问题的症状。真正的问题是你为什么一开始会闪烁?还是没有闪烁?
  • 如果我在添加节点的上方使用我的意思是(.Nodes.Add)就足够了吗??
  • @Jeremy Thompson 你的意思是第一名根本不需要包含更少的节点??但是任何使用它的方式都是最佳实践??
  • 添加/分配您正在使用的根节点,仅在构建树之后。 IIRC 这要快得多。

标签: c# winforms treeview


【解决方案1】:

Begin/EndUpdate() 方法并非旨在消除闪烁。在 EndUpdate() 处闪烁是不可避免的,它会重新绘制控件。它们旨在加速添加大量节点,默认情况下会很慢,因为每个项目都会导致重绘。您将它们放在 for 循环中使情况变得更糟,将它们移到外面以立即改进。

这可能足以解决您的问题。但是你可以做得更好,抑制闪烁需要双缓冲。 .NET TreeView 类覆盖 DoubleBuffered 属性并隐藏它。这是一个历史意外,原生 Windows 控件仅在 Windows XP 及更高版本中支持双缓冲。 .NET 曾经支持 Windows 2000 和 Windows 98。

如今,这不再完全相关。您可以通过从 TreeView 派生您自己的类来将其放回原处。向您的项目添加一个新类并粘贴如下所示的代码。编译。将新控件从工具箱顶部拖放到窗体上,替换现有的 TreeView。效果非常明显,尤其是在滚动时。

using System;
using System.Windows.Forms;
using System.Runtime.InteropServices;

class BufferedTreeView : TreeView {
    protected override void OnHandleCreated(EventArgs e) {
       SendMessage(this.Handle, TVM_SETEXTENDEDSTYLE, (IntPtr)TVS_EX_DOUBLEBUFFER, (IntPtr)TVS_EX_DOUBLEBUFFER);
        base.OnHandleCreated(e);
    }
    // Pinvoke:
    private const int TVM_SETEXTENDEDSTYLE = 0x1100 + 44;
    private const int TVM_GETEXTENDEDSTYLE = 0x1100 + 45;
    private const int TVS_EX_DOUBLEBUFFER = 0x0004;
    [DllImport("user32.dll")]
    private static extern IntPtr SendMessage(IntPtr hWnd, int msg, IntPtr wp, IntPtr lp);
}

【讨论】:

  • MSDN 建议您对 TVM_SETEXTENDEDSTYLE 的使用不太正确;根据msdn.microsoft.com/en-us/library/windows/desktop/…,WPARAM 是掩码,LPARAM 是标志。所以跳过旧样式,只做 SendMessage(this.Handle, TVM_SETEXTENDEDSTYLE, (IntPtr)TVS_EX_DOUBLEBUFFER, (IntPtr)TVS_EX_DOUBLEBUFFER);
  • 呃,确实。我正在使用记录此错误的 MSDN 库的旧副本。感谢您的正确!
【解决方案2】:

如果您像我一样是新手并且在 vb.net 中需要它,这里是 @Hans Passant 的答案。我用过,变化很大

Protected Overrides Sub OnHandleCreated(ByVal e As EventArgs)
    SendMessage(Me.Handle, TVM_SETEXTENDEDSTYLE, CType(TVS_EX_DOUBLEBUFFER, IntPtr), CType(TVS_EX_DOUBLEBUFFER, IntPtr))
    MyBase.OnHandleCreated(e)
End Sub

Private Const TVM_SETEXTENDEDSTYLE As Integer = &H1100 + 44
Private Const TVM_GETEXTENDEDSTYLE As Integer = &H1100 + 45
Private Const TVS_EX_DOUBLEBUFFER As Integer = &H4
<DllImport("user32.dll")>
Private Shared Function SendMessage(ByVal hWnd As IntPtr, ByVal msg As Integer, ByVal wp As IntPtr, ByVal lp As IntPtr) As IntPtr
End Function

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2023-04-02
    • 1970-01-01
    • 2021-12-17
    • 2012-08-22
    • 2015-04-25
    • 2011-02-06
    • 2012-05-13
    相关资源
    最近更新 更多