1

I have a WinForms TreeView with a vertical scroll bar. Sometimes I have to reset the nodes and fill the tree again. I do this in the middle of BeginUpdate/EndUpdate calls. But when I call Nodes.Clear(), the scroll bar is recalculated to account for the clearing of nodes, and after populating the Nodes and calling EndUpdate is recalculated again. This produces an ugly flickering.

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

I supposed calling BeginUpdate/EndUpdate prevented all repainting of the TreeView. The question then is whether my guess is wrong and this is not so, and in that case what whould be the solution.

(I´m using Visual Basic, .NET framework 4.6.1)

DanielB
  • 117
  • 2
  • 9
  • 1
    That's how the beast works, nothing you can do about it. I won't mention LockWindowUpdate(). That is not usually called "flicker", you might be complaining about the repaint that happens after EndUpdate(). Stuffing hundreds of nodes into the tree is not a grand idea. Maybe double-buffering can help, https://stackoverflow.com/a/10364283/17034 – Hans Passant Sep 20 '20 at 12:37
  • + Note that `treeView.Nodes.Clear()` already calls `BeginUpdate()` / `EndUpdate()` on the owner TreeView if you have more than 200 nodes, so you're potentially calling it twice. `EndUpdate()` sends `WM_SETREDRAW` and then `Invalidate()`. You need to have a lot of Nodes there to see this *effect*. + What `CreateNodes()` is doing is undefined. – Jimi Sep 20 '20 at 12:56
  • @HansPassant I´m already using double buffering, exactly from your linked answer. The effect is that the scroll bar enlarges and the nodes appear painted twice in a shifted position, just in the Nodes.Clear() moment. After EndUpdate the scroll and the nodes are painted correctly, but the effect is awful. This problem appears with an amount of nodes enough to fill the actual size of the treeview. – DanielB Sep 20 '20 at 17:24
  • @Jimi the effect appears exactly after calling Nodes.Clear() and before enter CreateNodes, which just repopulates the tree with the new data. I tried removing the nodes one by one but same thing. This happen with a hundred nodes. – DanielB Sep 20 '20 at 17:43
  • With a hundred nodes? No, this doesn't happen in normal conditions. You don't even need any kind of double buffering. Are you owner-drawing this TreeView? Or something else that depends on/relates to the TreeView that is drawing something, or data fetchers that get called without reason, code in the TreeView's event handlers that gets mad when these changes occur and maybe cause cascading events when nodes are added/removed? – Jimi Sep 20 '20 at 17:53
  • @Jimi Yes, it's an owner drawing TV. Whatever is happening happens inside the execution of Nodes.Clear, I can see in the debugger the effect in that exact moment. Following the mention of HansPassant about LockWindowUpdate, I came with SendMessage(Parent.Handle, WM_SETREDRAW, False, 0) and that works perfectly. Does it say anything to you? – DanielB Sep 20 '20 at 18:08
  • 1
    `SendMessage(Parent.Handle, WM_SETREDRAW, False, 0)` is exactly what `BeginUpdate()` is doing. In this case, you prevent the Parent from being redrawn. Your `DrawItem` procedure is lacking a check on what's happening when the event is raised. It's not exactly something new, it depends on the way a TreeView draws its Items: you may receive the same event for the same item more than once and, *maybe*, you forget to check what is the Item or the Node state at that time. So you draw it when you should not. That code needs a lot of debugging even when you know what's going on. – Jimi Sep 20 '20 at 18:28
  • 1
    You can notice that the owner-draw proc is not *perfect* when you can see the Nodes *flicker* a bit when selected even when you have very few Items. If you click on a Node and you see a small *motion* or perceive a small delay, then your procedure is not correct: you're drawing more that you should. This is pretty common. – Jimi Sep 20 '20 at 18:34
  • I commented the SendMessage but DrawNode is not entered until EndUpdate. What you say about owner draw proc is true. Until I managed to get the DoubleBuffered right I had that problem. Do you have any links to a perfect implementation? All those I see seem not to be that good. – DanielB Sep 20 '20 at 18:41
  • 1
    Have you read https://www.codeproject.com/articles/19847/fasttreeview ? – Caius Jard Sep 21 '20 at 08:36

1 Answers1

0

A trick helped me. It looks like this:

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

By collapsing the just-added root node, performance has been increased 20 times in my case. BTW, I have 2 trees in the same form. The BeginUpdate in the first works perfect, and the one in the second does nothing. I don't know why.

cheny
  • 2,545
  • 1
  • 24
  • 30