none
Possible bug in .NET TreeView? TreeNode checked state inconsistent

    Question

  • (is crosspost at CodeProject.com, no replies)

    I'm working with a .NET System.Windows.Forms.TreeView (both .NET 2.0 and 3.5) and have a problem with the check boxes not correctly affecting/reflecting the TreeNode's Checked state.

    I've enabled checkboxes and have event handlers for BeforeCheck and AfterCheck to act whenever a TreeNode's checkbox is checked or unchecked. My problem is that if you place the mouse pointer directly on a node's checkbox and double-click, the checkbox's visible checked state toggles, but the Checked state of the corresponding TreeNode does not actually change. Further the TreeView's BeforeCheck and AfterCheck handlers are never invoked [this actually seems consistent and follows from the observation the these events are raised exactly and only when anything actually changes the TreeNode.Checked property, not the state of the visible check box]. A single(left)-click on the check box works properly: the Before/AfterCheck handlers are invoked and the TreeNode's Checked state changes correctly.

    Double-clicking elsewhere on the displayed node toggles the expanded/collapsed state (as I assume it's suposed to do).

    I've tried to find a TreeView event handler that will allow me to catch a double-click directly on the checkbox and either ignore it or modify the node's checked state myself. But I've been unable to find an event handle to catch this.

    Is this a known bug? Could there be something I'm doing wrong? It gives my application a rather annoying incorrect behavior and I really don't want to abandon the use of TreeView and have to reimplement a correct "TreeView"!

    Can anyone steer me toward any information about this behavior of TreeView?

    Thanks in advance.

    P.S. using C#, Studio 2008, running on Vista Ultimate 32bit.  Answered below.

    • Edited by johnk310 Monday, June 01, 2009 4:12 PM
    Sunday, May 31, 2009 6:51 PM

Answers

  • Yes, this is a bug in Vista.  Add a new class to your project and paste the code shown below.  Compile.  Drop the new control from the toolbox onto your form.

    using System;
    using System.Windows.Forms;

    public class MyTreeView : TreeView {
      protected override void WndProc(ref Message m) {
        // Suppress WM_LBUTTONDBLCLK
        if (m.Msg == 0x203) { m.Result = IntPtr.Zero; }
        else base.WndProc(ref m);
      }
    }

    Hans Passant.
    • Marked as answer by johnk310 Monday, June 01, 2009 4:04 PM
    Sunday, May 31, 2009 8:34 PM
    Moderator

All replies

  • Yes, this is a bug in Vista.  Add a new class to your project and paste the code shown below.  Compile.  Drop the new control from the toolbox onto your form.

    using System;
    using System.Windows.Forms;

    public class MyTreeView : TreeView {
      protected override void WndProc(ref Message m) {
        // Suppress WM_LBUTTONDBLCLK
        if (m.Msg == 0x203) { m.Result = IntPtr.Zero; }
        else base.WndProc(ref m);
      }
    }

    Hans Passant.
    • Marked as answer by johnk310 Monday, June 01, 2009 4:04 PM
    Sunday, May 31, 2009 8:34 PM
    Moderator
  • Wow!  Thank you so much.  I'll try it ASAP (and I'll do it on XP & 7, too).  I did forget to mention I'm building, debugging, testing on Vista.  But app will run on XP, 7, etc. eventually.

    P.S. Fix verified on Vista Ultimate 32, XP Pro 32, 7 Beta 1 32.  Thank you!
    Monday, June 01, 2009 4:10 PM
  • I have had the same experience as johnk310

    Thanks nobugz for the work around, works for me on: Vista Business 32, .Net 2.0

    Is there are bug report for this at Microsoft Connect?
    I cannot seem to find one for it and was thinking of opening one.
    Friday, September 18, 2009 2:07 AM
  • Hi

    Your solution work fine. Thanks.
    But i have other problem:

    I need disable treenodes checkbox.
    With treeview work fine: 

    treeview.BeforeCheck += new TreeViewCancelEventHandler(this.processBeforeCheck);
    public void processBeforeCheck(object sender, TreeViewCancelEventHandler e)
    { e.cancel = true; }

    But mytreeview not have the option e.cancel
    How to resolve my problem?

    Thanks

    Sunday, November 01, 2009 12:27 PM
  • Problem solved:

    treeview1.BeforeCheck += new TreeViewCancelEventHandler(this.processaAntesCheck);

    public void processaAntesCheck(object sender, CancelEventArgs e)
    { e.Cancel = true; }
    Monday, November 02, 2009 6:55 PM
  • The problem with this solution is, that it disables double clicks for this control altogether. Is there a solution that specifically handles the checkboxes?
    Friday, March 26, 2010 10:40 AM
  • Hi,

     

    could you please provide a code which solves the same problem but in c++.

     

    Thank you in advance.

    Stanislav

    Friday, May 21, 2010 3:25 PM
  • does anybody know if this issue was fixed in .NET 4.0?
    Tuesday, July 06, 2010 7:15 PM
  • Yes, this is a bug in Vista.  Add a new class to your project and paste the code shown below.  Compile.  Drop the new control from the toolbox onto your form.

    using System;
    using System.Windows.Forms;

    public class MyTreeView : TreeView {
      protected override void WndProc(ref Message m) {
        // Suppress WM_LBUTTONDBLCLK
        if (m.Msg == 0x203) { m.Result = IntPtr.Zero; }
        else base.WndProc(ref m);
      }
    }

    Hans Passant.


    This was exactly what I needed having experienced this treeview bug.  Under some cirtumstances events would fire when double-clicking but often they would not, this solution was an instant fix to my issue.

    Many thanks

    Mark

    Thursday, August 12, 2010 9:59 AM
  • The problem with this solution is, that it disables double clicks for this control altogether. Is there a solution that specifically handles the checkboxes?


    I had the same issue, here is my solution, modified from Hans Passant. Basically it stops any double-clicking behavior in the treeview for a second as soon as a checkbox has been checked.

    P.S. thanx Hans Passant for your solution in the first place!

     

    public partial class MyTreeView : TreeView
            {

                public long DoubleclickTicks = 0;
                public object DoubleclickTicksLock = new object();

                protected override void WndProc(ref Message m)
                {
                    // Suppress WM_LBUTTONDBLCLK
                    if (m.Msg == 0x203)
                    {
                        long ticksdifference;
                        lock (DoubleclickTicksLock)
                        {
                            ticksdifference = DateTime.Now.Ticks - DoubleclickTicks;
                        }
                        if (ticksdifference < TimeSpan.TicksPerSecond)
                            m.Result = IntPtr.Zero;
                        else
                            base.WndProc(ref m);
                    }
                    else base.WndProc(ref m);
                }
            }

            private void yourTreeView_AfterCheck(object sender, TreeViewEventArgs e)
            {

                lock (yourTreeView.DoubleclickTicksLock)
                {
                    yourTreeView.DoubleclickTicks = DateTime.Now.Ticks;
                }

              // Your stuff here

            }

    I am a beginning .NET user, please reply if there is anything illegal done here.

     

    Michael.

     

    • Proposed as answer by swiss matt Monday, August 23, 2010 3:28 PM
    Thursday, August 19, 2010 11:37 AM
  • Sorry, I pressed the wrong button - I meant to reply, not Propse as answer!

    I fixed it by disabling the double-click only when the checkbox was clicked:

     public partial class CheckboxTreeView : TreeView
     {

      ...

      private const int WM_LBUTTONDBLCLK = 0x0203;
      private const int WM_RBUTTONDOWN = 0x0204;

            protected override void WndProc(ref Message m)
            {
       if(m.Msg == WM_LBUTTONDBLCLK)
                {
        // disable double-click on checkbox to fix Microsoft Vista bug
        TreeViewHitTestInfo tvhti = HitTest(new Point((int)m.LParam));
        if(tvhti != null && tvhti.Location == TreeViewHitTestLocations.StateImage)
        {
         m.Result = IntPtr.Zero;
         return;
        }
                }
       else if(m.Msg == WM_RBUTTONDOWN)
       {
        // set focus to node on right-click - another Microsoft bug?
        TreeViewHitTestInfo tvhti = HitTest(new Point((int)m.LParam));
        if(tvhti != null)
         this.SelectedNode = tvhti.Node; 
       }
       base.WndProc(ref m);
            }
      ...
     } 

    Monday, August 23, 2010 3:33 PM

  • Sorry, I pressed the wrong button - I meant to reply, not Propse as answer!

    I fixed it by disabling the double-click only when the checkbox was clicked:

     public partial class CheckboxTreeView : TreeView
     {

      ...

      private const int WM_LBUTTONDBLCLK = 0x0203;
      private const int WM_RBUTTONDOWN = 0x0204;

            protected override void WndProc(ref Message m)
            {
       if(m.Msg == WM_LBUTTONDBLCLK)
                {
        // disable double-click on checkbox to fix Microsoft Vista bug
        TreeViewHitTestInfo tvhti = HitTest(new Point((int)m.LParam));
        if(tvhti != null && tvhti.Location == TreeViewHitTestLocations.StateImage)
        {
         m.Result = IntPtr.Zero;
         return;
        }
                }
       else if(m.Msg == WM_RBUTTONDOWN)
       {
        // set focus to node on right-click - another Microsoft bug?
        TreeViewHitTestInfo tvhti = HitTest(new Point((int)m.LParam));
        if(tvhti != null)
         this.SelectedNode = tvhti.Node; 
       }
       base.WndProc(ref m);
            }
      ...
     } 

    Thanks so much!! You saved me!!!

    Ciaoo :)

     

    Wednesday, September 14, 2011 4:15 PM
  • Hi, encounter same problem here.

    Try to resolve with all the suggested solution. But still unable to resolve the problem.

    One thing very weird that i realize that, WndProc Message never return WM_LBUTTONDBLCLK = 0x0203.

    Every time i double click on the treeview check box, first it will trigger the treeview_beforecheck and treeview_aftercheck event.

    Then the treeview check box show inconsistent check stage and the 2 event wont be trigger.

     

    Everytime i double click, it will return this 2 value for WndProc

    WM_PARENTNOTIFY = 0x210 and WM_MOUSEACTIVATE = 0x0021.

     

    My Environment.

    Window 7, Visual Studio 2010 .NET Framework 4.

    Monday, September 26, 2011 11:42 AM