1

TL;DR: Need a way to disable scrolling in a TreeView temporarily without any flickering.

Coding a C# plugin. I have a TreeView control that displays a list of files open in an editor application.

The TreeView is part of a UserControl loaded by the application and handles events called by the application, such as file change, upload to a server, etc.

I have the MouseEnter and MouseLeave events handled.

The MouseEnter sets the focus to the TreeView, which is needed so that the double-click on the node works correctly (i.e. the application gives the input only after a mouse-click, which means a double-click becomes a single click; additionally a right-click if the mouse was moved sometimes returned the wrong node). With the focus set at the MouseEnter all works as expected.

The MouseLeave hides any custom tooltip shown.

The problem that I have not been able to solve however is a problem with scrolling. If the number of nodes in the TreeView are too many, the TreeView needs to be scrolled. I am using the EnsureVisible() method to achieve the necessary scrolling to the currently active file in the editor application. This part works perfectly.

The problem comes about when the user is scrolling with the mouse wheel while the mouse is not in the area of the TreeView. And it is a problem because MouseEnter sets the focus to the TreeView so that even if the scroll is done while the mouse pointer is in the active document, the focus being in the TreeView scrolls the TreeView, which is not wanted. (Scrolling with the scroll bar is okay, of course, since the user intends to scroll the TreeView.)

I tried more avenues to handle this but none of them is adequate:

  1. The first was to try to handle the MouseWheel event. But the problem is that I found no way to prevent the scroll from executed, since the MouseEventArgs do not have a Cancel field, and the Delta field is read-only. So this did not help. Here is the code for the event handler:

private void treeView1_MouseWheel(object sender, MouseEventArgs e)
{
    if (!(this.Width > e.Location.X &&
          -1 < e.Location.X &&
          this.Height > e.Location.Y &&
          -1 < e.Location.Y))
    {
            //this is where the cancel should go;
            return;
    }
}
  1. The other avenue that I tried and I somewhat managed to handle this problem with is to set the Scrollable property to false in the MouseLeave event handler and I set it to true in the MouseEnter. This does the trick, but it has the side effect that change to the Scrollable property automatically calls the RecreateHandle() method of the Control class and because the nodes collapse this causes a flicker. Here is the code for the two event handlers:

private void treeView1_MouseEnter(object sender, EventArgs e)
{
    treeView1.BeginUpdate(); 
    treeView1.Focus();
    treeView1.Scrollable = true;
    treeView1.ExpandAll();
    treeView1.EndUpdate();
}

private void treeView1_MouseLeave(object sender, EventArgs e)
{
    //this first part of the code turns of the custom tooltip if certain conditions are true
    if ((_mousePosOrig.Y - MousePosition.Y < 0 | MousePosition.Y - _mousePosOrig.Y < 15)
        & Math.Abs(MousePosition.X - _mousePosOrig.X) < 30
        & Math.Abs(MousePosition.Y - _mousePosOrig.Y) < 25) { }
    else
    {
        toolTip1.RemoveAll();
        _IstoolTipOn = false;
    }

    //here we turn of the scrolling
    treeView1.BeginUpdate();
    treeView1.Scrollable = false;
    treeView1.ExpandAll();
    treeView1.EndUpdate();
}

As you can see, I tried the BeginUpdate() method, but it does not cure the flicker either.

Can anyone please help resolving this? Either giving me a clue on how to handle the flicker or on how to disable the scroll in some other way.

ib11
  • 2,530
  • 3
  • 22
  • 55
  • 1
    You in fact can cancel the mousewheel event, [but it takes a cast](http://stackoverflow.com/a/6987339/17034). TreeView does in fact support double-buffering to eliminate flicker, [but it needs to be re-enabled](http://stackoverflow.com/a/10364283/17034). Do watch out for Win10, it changed the way mousewheel notifications are delivered. Now sending them to the control that is hovered instead of the control that has the focus. – Hans Passant Apr 22 '17 at 08:03
  • @HansPassant - thank you. The links were enlightening, especially the "cast" one. Adding the cast actually made solution 1 the solution as with `(HandledMouseEventArgs)e.Handled` the event was not passed on and the scroll did not get executed. Do you want to put the answer as the answer I can accept it? – ib11 Apr 23 '17 at 19:30

0 Answers0