TreeView.cs source code in C# .NET

Source code for the .NET framework in C#

                        

Code:

/ 4.0 / 4.0 / untmp / DEVDIV_TFS / Dev10 / Releases / RTMRel / ndp / fx / src / WinForms / Managed / System / WinForms / TreeView.cs / 1305376 / TreeView.cs

                            //------------------------------------------------------------------------------ 
// 
//     Copyright (c) Microsoft Corporation.  All rights reserved.
// 
//----------------------------------------------------------------------------- 

/* 
 */ 
namespace System.Windows.Forms {
    using System.Runtime.Remoting; 
    using System.Runtime.InteropServices;
    using System.Diagnostics;
    using System.Diagnostics.CodeAnalysis;
    using System; 
    using System.Security.Permissions;
    using System.Security; 
    using System.Drawing; 
    using System.Windows.Forms.Internal;
    using System.Drawing.Design; 
    using System.ComponentModel;
    using System.ComponentModel.Design;
    using System.Collections;
    using Microsoft.Win32; 
    using System.Reflection;
    using System.Windows.Forms.Layout; 
    using System.Globalization; 
    using System.Windows.Forms.VisualStyles;
 
    /// 
    /// 
    ///    
    ///       Displays a hierarchical list of items, or nodes. Each 
    ///       node includes a caption and an optional bitmap. The user can select a node. If
    ///       it has sub-nodes, the user can collapse or expand the node. 
    /// 
    ///    
    ///  
    [
    ComVisible(true),
    ClassInterface(ClassInterfaceType.AutoDispatch),
    DefaultProperty("Nodes"), 
    DefaultEvent("AfterSelect"),
    Docking(DockingBehavior.Ask), 
    Designer("System.Windows.Forms.Design.TreeViewDesigner, " + AssemblyRef.SystemDesign), 
    SRDescription(SR.DescriptionTreeView)
    ] 
    public class TreeView : Control {

        private static readonly int MaxIndent = 32000;      // Maximum allowable TreeView indent
        private static readonly string backSlash = "\\"; 
        private const int DefaultTreeViewIndent = 19;
 
        private DrawTreeNodeEventHandler onDrawNode; 
        private NodeLabelEditEventHandler onBeforeLabelEdit;
        private NodeLabelEditEventHandler onAfterLabelEdit; 
        private TreeViewCancelEventHandler onBeforeCheck;
        private TreeViewEventHandler onAfterCheck;
        private TreeViewCancelEventHandler onBeforeCollapse;
        private TreeViewEventHandler onAfterCollapse; 
        private TreeViewCancelEventHandler onBeforeExpand;
        private TreeViewEventHandler onAfterExpand; 
        private TreeViewCancelEventHandler onBeforeSelect; 
        private TreeViewEventHandler onAfterSelect;
        private ItemDragEventHandler onItemDrag; 
        private TreeNodeMouseHoverEventHandler onNodeMouseHover;
        private EventHandler onRightToLeftLayoutChanged;

        internal TreeNode selectedNode = null; 
        private ImageList.Indexer imageIndexer;
        private ImageList.Indexer selectedImageIndexer; 
        private bool setOddHeight = false; 
        private TreeNode prevHoveredNode = null;
        private bool hoveredAlready  = false; 
        private bool rightToLeftLayout = false;

        [SuppressMessage("Microsoft.Reliability", "CA2006:UseSafeHandleToEncapsulateNativeResources")]
        private IntPtr hNodeMouseDown = IntPtr.Zero;//ensures we fire nodeclick on the correct node 

        private const int   TREEVIEWSTATE_hideSelection             = 0x00000001; 
        private const int   TREEVIEWSTATE_labelEdit                 = 0x00000002; 
        private const int   TREEVIEWSTATE_scrollable                = 0x00000004;
        private const int   TREEVIEWSTATE_checkBoxes                = 0x00000008; 
        private const int   TREEVIEWSTATE_showLines                 = 0x00000010;
        private const int   TREEVIEWSTATE_showPlusMinus             = 0x00000020;
        private const int   TREEVIEWSTATE_showRootLines             = 0x00000040;
        private const int   TREEVIEWSTATE_sorted                    = 0x00000080; 
        private const int   TREEVIEWSTATE_hotTracking               = 0x00000100;
        private const int   TREEVIEWSTATE_fullRowSelect             = 0x00000200; 
        private const int   TREEVIEWSTATE_showNodeToolTips          = 0x00000400; 
        private const int   TREEVIEWSTATE_doubleclickFired          = 0x00000800;
        private const int   TREEVIEWSTATE_mouseUpFired              = 0x00001000; 
        private const int   TREEVIEWSTATE_showTreeViewContextMenu   = 0x00002000;
        private const int   TREEVIEWSTATE_lastControlValidated      = 0x00004000;
        private const int   TREEVIEWSTATE_stopResizeWindowMsgs      = 0x00008000;//VSWhidbey 466949
        private const int   TREEVIEWSTATE_ignoreSelects             = 0x00010000;//VSWhidbey 384294, 490763. 

        // PERF: take all the bools and put them into a state variable 
        private System.Collections.Specialized.BitVector32          treeViewState; // see TREEVIEWSTATE_ consts above 

 
        /// 
        /// 
        internal ImageList.Indexer ImageIndexer {
             get { 
                if (imageIndexer == null) {
                    imageIndexer = new ImageList.Indexer(); 
                } 
                imageIndexer.ImageList = ImageList;
                return imageIndexer; 
             }
        }

        ///  
        /// 
        internal ImageList.Indexer SelectedImageIndexer { 
             get { 
                   if (selectedImageIndexer == null) {
                        selectedImageIndexer = new ImageList.Indexer(); 
                   }
                   selectedImageIndexer.ImageList = ImageList;

                   return selectedImageIndexer; 
             }
        } 
 
        private ImageList imageList;
        private int indent = -1; 
        private int itemHeight = -1;
        private string pathSeparator = backSlash;
        private BorderStyle borderStyle = System.Windows.Forms.BorderStyle.Fixed3D;
 
        internal TreeNodeCollection nodes = null;
        internal TreeNode editNode; 
        internal TreeNode root; 
        internal Hashtable nodeTable = new Hashtable();
        internal bool nodesCollectionClear = false; //this is set when the treeNodeCollection is getting cleared and used by TreeView 
        private MouseButtons downButton;
        private TreeViewDrawMode drawMode = TreeViewDrawMode.Normal;

        //Properties newly added to TreeView.... 
        private ImageList internalStateImageList;
        private TreeNode topNode; 
        private ImageList stateImageList; 
        private Color lineColor;
        private string controlToolTipText = null; 

        // Sorting
        private IComparer treeViewNodeSorter = null;
 

        //Events 
        private TreeNodeMouseClickEventHandler onNodeMouseClick; 
        private TreeNodeMouseClickEventHandler onNodeMouseDoubleClick;
 
        /// 
        /// 
        ///     Creates a TreeView control
        ///  
        public TreeView()
        : base() { 
 
            this.treeViewState = new System.Collections.Specialized.BitVector32(TREEVIEWSTATE_showRootLines |
                                                                                TREEVIEWSTATE_showPlusMinus | 
                                                                                TREEVIEWSTATE_showLines |
                                                                                TREEVIEWSTATE_scrollable |
                                                                                TREEVIEWSTATE_hideSelection);
 
            root = new TreeNode(this);
 
            // TreeView must always have an ImageIndex. 
            SelectedImageIndexer.Index = 0;
            ImageIndexer.Index = 0; 

            SetStyle(ControlStyles.UserPaint, false);
            SetStyle(ControlStyles.StandardClick, false);
            SetStyle(ControlStyles.UseTextForAccessibility, false); 
        }
 
        ///  
        /// 
        ///     The background color for this control. Specifying null for 
        ///     this parameter sets the
        ///     control's background color to its parent's background color.
        /// 
        public override Color BackColor { 
            get {
                if (ShouldSerializeBackColor()) { 
                    return base.BackColor; 
                }
                else { 
                    return SystemColors.Window;
                }
            }
 
            set {
                base.BackColor = value; 
                if (IsHandleCreated) { 
                    SendMessage(NativeMethods.TVM_SETBKCOLOR, 0, ColorTranslator.ToWin32(BackColor));
 
                    // This is to get around a problem in the comctl control where the lines
                    // connecting nodes don't get the new BackColor.  This messages forces
                    // reconstruction of the line bitmaps without changing anything else.
                    SendMessage(NativeMethods.TVM_SETINDENT, Indent, 0); 
                }
            } 
        } 

        ///  
        /// 
        ///    [To be supplied.]
        /// 
        ///  
        [Browsable(false), EditorBrowsable(EditorBrowsableState.Never)]
        public override Image BackgroundImage { 
            get { 
                return base.BackgroundImage;
            } 
            set {
                base.BackgroundImage = value;
            }
        } 

        ///  
        ///  
        [Browsable(false), EditorBrowsable(EditorBrowsableState.Never)]
        new public event EventHandler BackgroundImageChanged { 
            add {
                base.BackgroundImageChanged += value;
            }
            remove { 
                base.BackgroundImageChanged -= value;
            } 
        } 

 
        /// 
        /// 
        ///    [To be supplied.]
        ///  
        /// 
        [Browsable(false), EditorBrowsable(EditorBrowsableState.Never)] 
        public override ImageLayout BackgroundImageLayout { 
            get {
                return base.BackgroundImageLayout; 
            }
            set {
                base.BackgroundImageLayout = value;
            } 
        }
 
        ///  
        /// 
        [Browsable(false), EditorBrowsable(EditorBrowsableState.Never)] 
        new public event EventHandler BackgroundImageLayoutChanged {
            add {
                base.BackgroundImageLayoutChanged += value;
            } 
            remove {
                base.BackgroundImageLayoutChanged -= value; 
            } 
        }
 
        /// 
        /// 
        ///     The border style of the window.
        ///  
        [
        SRCategory(SR.CatAppearance), 
        DefaultValue(BorderStyle.Fixed3D), 
        DispId(NativeMethods.ActiveX.DISPID_BORDERSTYLE),
        SRDescription(SR.borderStyleDescr) 
        ]
        public BorderStyle BorderStyle {
            get {
                return borderStyle; 
            }
 
            set { 
                if (borderStyle != value) {
                    //verify that 'value' is a valid enum type... 

                    //valid values are 0x0 to 0x2
                    if (!ClientUtils.IsEnumValid(value, (int)value, (int)BorderStyle.None, (int)BorderStyle.Fixed3D))
                    { 
                        throw new InvalidEnumArgumentException("value", (int)value, typeof(BorderStyle));
                    } 
 
                    borderStyle = value;
                    UpdateStyles(); 
                }
            }
        }
 
        /// 
        ///  
        ///     The value of the CheckBoxes property. The CheckBoxes 
        ///     property determines if check boxes are shown next to node in the
        ///     tree view. 
        /// 
        [
        SRCategory(SR.CatAppearance),
        DefaultValue(false), 
        SRDescription(SR.TreeViewCheckBoxesDescr)
        ] 
        public bool CheckBoxes { 
            get {
                return treeViewState[TREEVIEWSTATE_checkBoxes]; 
            }

            set {
                if (CheckBoxes != value) { 
                    treeViewState[TREEVIEWSTATE_checkBoxes] = value;
                    if (IsHandleCreated) { 
                        // Going from true to false requires recreation 
                        if (CheckBoxes) {
                            UpdateStyles(); 
                        } else {
                            // Reset the Checked state after setting the checkboxes (this was Everett behavior)
                            // The implementation of the TreeNode.Checked property has changed in Whidbey
                            // So we need to explicit set the Checked state to false to keep the everett behavior. 
                            UpdateCheckedState(root, false);
                            RecreateHandle(); 
                        } 
                    }
                } 
            }
        }

        ///  
        /// 
        ///  
        ///  
        protected override CreateParams CreateParams {
            [SecurityPermission(SecurityAction.LinkDemand, Flags=SecurityPermissionFlag.UnmanagedCode)] 
            get {
                CreateParams cp = base.CreateParams;
                cp.ClassName = NativeMethods.WC_TREEVIEW;
 

                // V#45599 Keep the scrollbar if we are just updating styles... 
                // 
                if (IsHandleCreated) {
                    int currentStyle = unchecked((int)((long)UnsafeNativeMethods.GetWindowLong(new HandleRef(this, Handle), NativeMethods.GWL_STYLE))); 
                    cp.Style |= (currentStyle & (NativeMethods.WS_HSCROLL | NativeMethods.WS_VSCROLL));
                }
                switch (borderStyle) {
                    case BorderStyle.Fixed3D: 
                        cp.ExStyle |= NativeMethods.WS_EX_CLIENTEDGE;
                        break; 
                    case BorderStyle.FixedSingle: 
                        cp.Style |= NativeMethods.WS_BORDER;
                        break; 
                }

                if (!Scrollable)
                    cp.Style |= NativeMethods.LVS_NOSCROLL; 

                if (!HideSelection) 
                    cp.Style |= NativeMethods.TVS_SHOWSELALWAYS; 
                if (LabelEdit)
                    cp.Style |= NativeMethods.TVS_EDITLABELS; 
                if (ShowLines)
                    cp.Style |= NativeMethods.TVS_HASLINES;
                if (ShowPlusMinus)
                    cp.Style |= NativeMethods.TVS_HASBUTTONS; 
                if (ShowRootLines)
                    cp.Style |= NativeMethods.TVS_LINESATROOT; 
                if (HotTracking) 
                    cp.Style |= NativeMethods.TVS_TRACKSELECT;
                if (FullRowSelect) 
                    cp.Style |= NativeMethods.TVS_FULLROWSELECT;
                if (setOddHeight) {
                    cp.Style |= NativeMethods.TVS_NONEVENHEIGHT;
                } 

                // Don't set TVS_CHECKBOXES here if the window isn't created yet. 
                // See OnHandleCreated for explanation 
                if (ShowNodeToolTips && IsHandleCreated && !DesignMode) {
                    cp.Style |= NativeMethods.TVS_INFOTIP; 
                }


                // Don't set TVS_CHECKBOXES here if the window isn't created yet. 
                // See OnHandleCreated for explanation
                if (CheckBoxes && IsHandleCreated) 
                    cp.Style |= NativeMethods.TVS_CHECKBOXES; 

                // Don't call IsMirrored from CreateParams. That will lead to some nasty problems, since 
                // IsMirrored ends up calling CreateParams - you dig!
                if (RightToLeft == RightToLeft.Yes) {
                    if (RightToLeftLayout == true) {
                        //We want to turn on mirroring for TreeView explicitly. 
                        cp.ExStyle |= NativeMethods.WS_EX_LAYOUTRTL;
                        //Don't need these styles when mirroring is turned on. 
                        cp.ExStyle &= ~(NativeMethods.WS_EX_RTLREADING | NativeMethods.WS_EX_RIGHT | NativeMethods.WS_EX_LEFTSCROLLBAR); 
                    }
                    else { 
                        cp.Style |= NativeMethods.TVS_RTLREADING;
                    }
                }
 
                return cp;
            } 
        } 

        ///  
        /// 
        ///     Deriving classes can override this to configure a default size for their control.
        ///     This is more efficient than setting the size in the control's constructor.
        ///  
        protected override Size DefaultSize {
            get { 
                return new Size(121, 97); 
            }
        } 

        /// 
        /// 
        ///     This property is overridden and hidden from statement completion 
        ///     on controls that are based on Win32 Native Controls.
        ///  
        [EditorBrowsable(EditorBrowsableState.Never)] 
        protected override bool DoubleBuffered {
            get { 
                return base.DoubleBuffered;
            }
            set {
                base.DoubleBuffered = value; 
            }
        } 
 
        /// 
        ///  
        ///     The current foreground color for this control, which is the
        ///     color the control uses to draw its text.
        /// 
        public override Color ForeColor { 
            get {
                if (ShouldSerializeForeColor()) { 
                    return base.ForeColor; 
                }
                else { 
                    return SystemColors.WindowText;
                }
            }
 
            set {
                base.ForeColor = value; 
                if (IsHandleCreated) 
                    SendMessage(NativeMethods.TVM_SETTEXTCOLOR, 0, ColorTranslator.ToWin32(ForeColor));
            } 
        }

        /// 
        ///  
        ///     Determines whether the selection highlight spans across the width of the TreeView.
        ///     This property will have no effect if ShowLines is true. 
        ///  
        [
        SRCategory(SR.CatBehavior), 
        DefaultValue(false),
        SRDescription(SR.TreeViewFullRowSelectDescr)
        ]
        public bool FullRowSelect { 
            get { return treeViewState[TREEVIEWSTATE_fullRowSelect];}
            set { 
                if (FullRowSelect != value) { 
                    treeViewState[TREEVIEWSTATE_fullRowSelect] = value;
                    if (IsHandleCreated) { 
                        UpdateStyles();
                    }
                }
            } 
        }
 
        ///  
        /// 
        ///     The HideSelection property specifies whether the selected node will 
        ///     be highlighted even when the TreeView loses focus.
        /// 
        [
        SRCategory(SR.CatBehavior), 
        DefaultValue(true),
        SRDescription(SR.TreeViewHideSelectionDescr) 
        ] 
        public bool HideSelection {
            get { 
                return treeViewState[TREEVIEWSTATE_hideSelection];
            }

            set { 
                if (HideSelection != value) {
                    treeViewState[TREEVIEWSTATE_hideSelection] = value; 
                    if (IsHandleCreated) { 
                        UpdateStyles();
                    } 
                }
            }
        }
 
        /// 
        ///  
        ///     The value of the HotTracking property. The HotTracking 
        ///     property determines if nodes are highlighted as the mousepointer
        ///     passes over them. 
        /// 
        [
        SRCategory(SR.CatBehavior),
        DefaultValue(false), 
        SRDescription(SR.TreeViewHotTrackingDescr)
        ] 
        public bool HotTracking { 
            get {
                return treeViewState[TREEVIEWSTATE_hotTracking]; 
            }

            set {
                if (HotTracking != value) { 
                    treeViewState[TREEVIEWSTATE_hotTracking] = value;
                    if (IsHandleCreated) { 
                        UpdateStyles(); 
                    }
                } 
            }
        }

        ///  
        /// 
        ///     The default image index for nodes in the tree view. 
        ///  
        [
        DefaultValue(-1), 
        SRCategory(SR.CatBehavior),
        Localizable(true),
        RefreshProperties(RefreshProperties.Repaint),
        TypeConverterAttribute(typeof(NoneExcludedImageIndexConverter)), 
        Editor("System.Windows.Forms.Design.ImageIndexEditor, " + AssemblyRef.SystemDesign, typeof(UITypeEditor)),
        SRDescription(SR.TreeViewImageIndexDescr), 
        RelatedImageList("ImageList") 
        ]
        public int ImageIndex { 
            get {
                if (imageList == null) {
                    return -1;
                } 
                if (ImageIndexer.Index >= imageList.Images.Count) {
                    return Math.Max(0, imageList.Images.Count - 1); 
                } 
                return ImageIndexer.Index;
            } 

            set {
                // If (none) is selected in the image index editor, we'll just adjust this to
                // mean image index 0. This is because a treeview must always have an image index - 
                // even if no imagelist exists we want the image index to be 0.
                // 
                if (value == -1) { 
                    value = 0;
                } 

                if (value < 0) {
                    throw new ArgumentOutOfRangeException("ImageIndex", SR.GetString(SR.InvalidLowBoundArgumentEx, "ImageIndex", value.ToString(CultureInfo.CurrentCulture), (0).ToString(CultureInfo.CurrentCulture)));
                } 

                if (ImageIndexer.Index != value) { 
                    ImageIndexer.Index = value; 
                    if (IsHandleCreated) {
                        RecreateHandle(); 
                    }
                }
            }
        } 

        ///  
        ///  
        ///     The default image index for nodes in the tree view.
        ///  
        [
        SRCategory(SR.CatBehavior),
        Localizable(true),
        TypeConverterAttribute(typeof(ImageKeyConverter)), 
        Editor("System.Windows.Forms.Design.ImageIndexEditor, " + AssemblyRef.SystemDesign, typeof(UITypeEditor)),
        DefaultValue(""), 
        RefreshProperties(RefreshProperties.Repaint), 
        SRDescription(SR.TreeViewImageKeyDescr),
        RelatedImageList("ImageList") 
        ]
        public string ImageKey {
            get {
                return ImageIndexer.Key; 
            }
 
            set { 
                if (ImageIndexer.Key != value) {
                    ImageIndexer.Key = value; 
                    if (String.IsNullOrEmpty(value) || value.Equals(SR.GetString(SR.toStringNone))) {
                        ImageIndex = (ImageList != null) ? 0:-1;
                    }
                    if (IsHandleCreated) { 
                        RecreateHandle();
                    } 
                } 
            }
        } 

        /// 
        /// 
        ///     Returns the image list control that is bound to the tree view. 
        /// 
        [ 
        SRCategory(SR.CatBehavior), 
        DefaultValue(null),
        SRDescription(SR.TreeViewImageListDescr), 
        RefreshProperties(RefreshProperties.Repaint)
        ]
        public ImageList ImageList {
            get { 
                return imageList;
            } 
            set { 
                if (value != imageList) {
 
                    DetachImageListHandlers();

                    imageList = value;
 
                    AttachImageListHandlers();
 
                    // Update TreeView's images 
                    //
                    if (IsHandleCreated) { 
                        SendMessage(NativeMethods.TVM_SETIMAGELIST, 0,
                                    value==null? IntPtr.Zero: value.Handle);
                        if (StateImageList != null && StateImageList.Images.Count > 0) {
                            SendMessage(NativeMethods.TVM_SETIMAGELIST, NativeMethods.TVSIL_STATE, 
                                    internalStateImageList.Handle);
                        } 
                    } 
                    UpdateCheckedState(root, true);
                } 
            }
        }

         private void AttachImageListHandlers() { 
              if (imageList != null) {
                  //NOTE: any handlers added here should be removed in DetachImageListHandlers 
                  imageList.RecreateHandle += new EventHandler(ImageListRecreateHandle); 
                  imageList.Disposed += new EventHandler(DetachImageList);
                  imageList.ChangeHandle += new EventHandler(ImageListChangedHandle); 
              }
          }

          private void DetachImageListHandlers() { 
              if (imageList != null) {
                  imageList.RecreateHandle -= new EventHandler(ImageListRecreateHandle); 
                  imageList.Disposed -= new EventHandler(DetachImageList); 
                  imageList.ChangeHandle -= new EventHandler(ImageListChangedHandle);
              } 
          }

          private void AttachStateImageListHandlers() {
              if (stateImageList != null) { 
                  //NOTE: any handlers added here should be removed in DetachStateImageListHandlers
                  stateImageList.RecreateHandle += new EventHandler(StateImageListRecreateHandle); 
                  stateImageList.Disposed += new EventHandler(DetachStateImageList); 
                  stateImageList.ChangeHandle += new EventHandler(StateImageListChangedHandle);
              } 
          }

          private void DetachStateImageListHandlers() {
              if (stateImageList != null) { 
                  stateImageList.RecreateHandle -= new EventHandler(StateImageListRecreateHandle);
                  stateImageList.Disposed -= new EventHandler(DetachStateImageList); 
                  stateImageList.ChangeHandle -= new EventHandler(StateImageListChangedHandle); 
              }
          } 


        /// 
        ///  
        ///     Returns the state image list control that is bound to the tree view.
        ///  
        [ 
        SRCategory(SR.CatBehavior),
        DefaultValue(null), 
        SRDescription(SR.TreeViewStateImageListDescr)
        ]
        public ImageList StateImageList {
            get { 
                return stateImageList;
            } 
            set { 
                if (value != stateImageList) {
 
                    DetachStateImageListHandlers();

                    stateImageList = value;
                    if (stateImageList != null && stateImageList.Images.Count > 0) { 
                        Image[] images = new Image[stateImageList.Images.Count + 1];
                        images[0] = stateImageList.Images[0]; 
                        for (int i = 1;  i <= stateImageList.Images.Count ; i++) { 
                            images[i] = stateImageList.Images[i -1];
                        } 
                        internalStateImageList = new ImageList();
                        internalStateImageList.Images.AddRange(images);
                    }
 

                    AttachStateImageListHandlers(); 
 
                    // Update TreeView's images
                    // 
                    if (IsHandleCreated)
                    {
                        if (stateImageList != null && stateImageList.Images.Count > 0)
                        { 
                            Debug.Assert(internalStateImageList != null, "internalStateImageList is null!!");
                            if (internalStateImageList != null) 
                            { 
                                SendMessage(NativeMethods.TVM_SETIMAGELIST, NativeMethods.TVSIL_STATE, internalStateImageList.Handle);
                            } 
                        }

                        // We need to update the checks
                        // and stateimage value for each node. 
                        UpdateCheckedState(root, true);
 
                        if((value == null || stateImageList.Images.Count == 0) && CheckBoxes) { 
                            // Requires Handle Recreate to force on the checkBoxes and states..
                            RecreateHandle(); 
                        }
                        else {
                            // The TreeView shows up the state imageList after sending this message even if the nodes dont have any stateImageIndex set.
                            // In order to avoid that we refresh nodes which would "reset" the images to none. 
                            // This causes flicker but gives us the right behavior
                            RefreshNodes(); 
                        } 
                    }
 

                }
            }
        } 

 
        ///  
        /// 
        ///     The indentation level in pixels. 
        /// 
        [
        Localizable(true),
        SRCategory(SR.CatBehavior), 
        SRDescription(SR.TreeViewIndentDescr)
        ] 
        public int Indent { 
            get {
                if (indent != -1) { 
                    return indent;
                }
                else if (IsHandleCreated) {
                    return unchecked( (int) (long)SendMessage(NativeMethods.TVM_GETINDENT, 0, 0)); 
                }
                return DefaultTreeViewIndent; 
            } 

            set { 
                if (indent != value) {
                    if (value < 0) {
                        throw new ArgumentOutOfRangeException("Indent", SR.GetString(SR.InvalidLowBoundArgumentEx, "Indent", (value).ToString(CultureInfo.CurrentCulture), (0).ToString(CultureInfo.CurrentCulture)));
                    } 
                    if (value > MaxIndent) {
                        throw new ArgumentOutOfRangeException("Indent", SR.GetString(SR.InvalidHighBoundArgumentEx, "Indent", (value).ToString(CultureInfo.CurrentCulture), (MaxIndent).ToString(CultureInfo.CurrentCulture))); 
                    } 
                    indent = value;
                    if (IsHandleCreated) { 
                        SendMessage(NativeMethods.TVM_SETINDENT, value, 0);
                        indent = unchecked( (int) (long)SendMessage(NativeMethods.TVM_GETINDENT, 0, 0));
                    }
                } 
            }
        } 
 
        /// 
        ///  
        ///     The height of every item in the tree view, in pixels.
        /// 
        [
        SRCategory(SR.CatAppearance), 
        SRDescription(SR.TreeViewItemHeightDescr)
        ] 
        public int ItemHeight { 
            get {
                if (itemHeight != -1) { 
                    return itemHeight;
                }

                if (IsHandleCreated) { 
                    return unchecked( (int) (long)SendMessage(NativeMethods.TVM_GETITEMHEIGHT, 0, 0));
                } 
                else { 
                    if (CheckBoxes && (DrawMode == TreeViewDrawMode.OwnerDrawAll)) {
                       return Math.Max(16, FontHeight + 3); 
                    }
                    return FontHeight + 3;
                }
            } 

            set { 
                if (itemHeight != value) { 
                    if (value < 1) {
                        throw new ArgumentOutOfRangeException("ItemHeight", SR.GetString(SR.InvalidLowBoundArgumentEx, "ItemHeight", (value).ToString(CultureInfo.CurrentCulture), (1).ToString(CultureInfo.CurrentCulture))); 
                    }
                    if (value >= Int16.MaxValue) {
                        throw new ArgumentOutOfRangeException("ItemHeight", SR.GetString(SR.InvalidHighBoundArgument, "ItemHeight", (value).ToString(CultureInfo.CurrentCulture), Int16.MaxValue.ToString(CultureInfo.CurrentCulture)));
                    } 
                    itemHeight = value;
                    if (IsHandleCreated) { 
                        if (itemHeight % 2 != 0) { 
                            setOddHeight = true;
                            try { 
                                RecreateHandle();
                            }
                            finally {
                                setOddHeight = false; 
                            }
                        } 
 
                        SendMessage(NativeMethods.TVM_SETITEMHEIGHT, value, 0);
                        itemHeight = unchecked( (int) (long)SendMessage(NativeMethods.TVM_GETITEMHEIGHT, 0, 0)); 
                    }
                }
            }
        } 

        ///  
        ///  
        ///     The LabelEdit property determines if the label text
        ///     of nodes in the tree view is editable. 
        /// 
        [
        SRCategory(SR.CatBehavior),
        DefaultValue(false), 
        SRDescription(SR.TreeViewLabelEditDescr)
        ] 
        public bool LabelEdit { 
            get {
                return treeViewState[TREEVIEWSTATE_labelEdit]; 
            }
            set {
                if (LabelEdit != value) {
                    treeViewState[TREEVIEWSTATE_labelEdit] = value; 
                    if (IsHandleCreated) {
                        UpdateStyles(); 
                    } 
                }
            } 
        }


        ///  
        /// 
        ///     This is the color of the lines that connect the nodes of the Treeview. 
        ///  
        [
        SRCategory(SR.CatBehavior), 
        SRDescription(SR.TreeViewLineColorDescr),
        DefaultValue(typeof(Color), "Black")
        ]
        public Color LineColor { 
            get {
                if (IsHandleCreated) { 
                    int intColor = unchecked((int)(long)SendMessage(NativeMethods.TVM_GETLINECOLOR, 0, 0)); 
                    return ColorTranslator.FromWin32(intColor);
                } 
                return lineColor;
            }
            set {
                if (lineColor != value) { 
                    lineColor = value;
                    if (IsHandleCreated) { 
                        SendMessage(NativeMethods.TVM_SETLINECOLOR, 0, ColorTranslator.ToWin32(lineColor)); 

                    } 
                }
            }
        }
 
        /// 
        ///  
        ///     The collection of nodes associated with this TreeView control 
        /// 
        [ 
        SRCategory(SR.CatBehavior),
        DesignerSerializationVisibility(DesignerSerializationVisibility.Content),
        Localizable(true),
        SRDescription(SR.TreeViewNodesDescr), 
        MergableProperty(false)
        ] 
        public TreeNodeCollection Nodes { 
            get {
                if (nodes == null) { 
                    nodes = new TreeNodeCollection(root);
                }
                return nodes;
            } 
        }
 
        ///  
        /// 
        ///  
        /// Indicates the drawing mode for the tree view.
        /// 
        /// 
        [ 
        SRCategory(SR.CatBehavior),
        DefaultValue(TreeViewDrawMode.Normal), 
        SRDescription(SR.TreeViewDrawModeDescr) 
        ]
        public TreeViewDrawMode DrawMode { 
            get {
                return drawMode;
            }
 
            set {
                //valid values are 0x0 to 0x2 
                if (!ClientUtils.IsEnumValid(value, (int)value, (int)TreeViewDrawMode.Normal, (int)TreeViewDrawMode.OwnerDrawAll)) 
                {
                    throw new InvalidEnumArgumentException("value", (int)value, typeof(TreeViewDrawMode)); 
                }

                if (drawMode != value) {
                    drawMode = value; 
                    Invalidate();
                    // We need to invalidate when the Control resizes when the we support custom draw. 
                    if (DrawMode == TreeViewDrawMode.OwnerDrawAll) 
                    {
                        SetStyle(ControlStyles.ResizeRedraw, true); 
                    }
                }
            }
        } 

        ///  
        ///  
        ///     The delimeter string used by TreeNode.getFullPath().
        ///  
        [
        SRCategory(SR.CatBehavior),
        DefaultValue("\\"),
        SRDescription(SR.TreeViewPathSeparatorDescr) 
        ]
        public string PathSeparator { 
            get { 
                return pathSeparator;
            } 
            set {
                pathSeparator = value;
            }
        } 

        ///  
        ///  
        ///    
        ///    [To be supplied.] 
        ///    
        /// 
        [
        Browsable(false), 
        EditorBrowsable(EditorBrowsableState.Never),
        DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden) 
        ] 
        public new Padding Padding {
            get { return base.Padding; } 
            set { base.Padding = value;}
        }

        [ 
        Browsable(false),
        EditorBrowsable(EditorBrowsableState.Never) 
        ] 
        public new event EventHandler PaddingChanged {
            add { base.PaddingChanged += value; } 
            remove { base.PaddingChanged -= value; }
        }

        ///  
        /// 
        ///     This is used for international applications where the language 
        ///     is written from RightToLeft. When this property is true, 
        //      and the RightToLeft is true, mirroring will be turned on on the form, and
        ///     control placement and text will be from right to left. 
        /// 
        [
        SRCategory(SR.CatAppearance),
        Localizable(true), 
        DefaultValue(false),
        SRDescription(SR.ControlRightToLeftLayoutDescr) 
        ] 
        public virtual bool RightToLeftLayout {
            get { 

                return rightToLeftLayout;
            }
 
            set {
                if (value != rightToLeftLayout) { 
                    rightToLeftLayout = value; 
                    using(new LayoutTransaction(this, this, PropertyNames.RightToLeftLayout)) {
                        OnRightToLeftLayoutChanged(EventArgs.Empty); 
                    }
                }
            }
        } 

 
        ///  
        /// 
        ///    [To be supplied.] 
        /// 
        [
        SRCategory(SR.CatBehavior),
        DefaultValue(true), 
        SRDescription(SR.TreeViewScrollableDescr)
        ] 
        public bool Scrollable { 
            get {
                return treeViewState[TREEVIEWSTATE_scrollable]; 
            }
            set {
                if (Scrollable != value) {
                    treeViewState[TREEVIEWSTATE_scrollable] = value; 
                    RecreateHandle();
                } 
            } 
        }
 
        /// 
        /// 
        ///     The image index that a node will display when selected.
        ///     The index applies to the ImageList referred to by the imageList property, 
        /// 
        [ 
        DefaultValue(-1), 
        SRCategory(SR.CatBehavior),
        TypeConverterAttribute(typeof(NoneExcludedImageIndexConverter)), 
        Localizable(true),
        Editor("System.Windows.Forms.Design.ImageIndexEditor, " + AssemblyRef.SystemDesign, typeof(UITypeEditor)),
        SRDescription(SR.TreeViewSelectedImageIndexDescr),
        RelatedImageList("ImageList") 
        ]
        public int SelectedImageIndex { 
            get { 
                if (imageList == null) {
                    return -1; 
                }
                if (SelectedImageIndexer.Index >= imageList.Images.Count) {
                    return Math.Max(0, imageList.Images.Count - 1);
                } 
                return SelectedImageIndexer.Index;
            } 
            set { 
                // If (none) is selected in the image index editor, we'll just adjust this to
                // mean image index 0. This is because a treeview must always have an image index - 
                // even if no imagelist exists we want the image index to be 0.
                //
                if (value == -1) {
                    value = 0; 
                }
 
                if (value < 0) { 
                    throw new ArgumentOutOfRangeException("SelectedImageIndex", SR.GetString(SR.InvalidLowBoundArgumentEx, "SelectedImageIndex", value.ToString(CultureInfo.CurrentCulture), (0).ToString(CultureInfo.CurrentCulture)));
                } 
                if (SelectedImageIndexer.Index != value) {
                    SelectedImageIndexer.Index = value;
                    if (IsHandleCreated) {
                        RecreateHandle(); 
                    }
                } 
            } 
        }
 
        /// 
        /// 
        ///     The default image index for nodes in the tree view.
        ///  
        [
        SRCategory(SR.CatBehavior), 
        Localizable(true), 
        TypeConverterAttribute(typeof(ImageKeyConverter)),
        Editor("System.Windows.Forms.Design.ImageIndexEditor, " + AssemblyRef.SystemDesign, typeof(UITypeEditor)), 
        DefaultValue(""),
        RefreshProperties(RefreshProperties.Repaint),
        SRDescription(SR.TreeViewSelectedImageKeyDescr),
        RelatedImageList("ImageList") 
        ]
        public string SelectedImageKey { 
            get { 
                return SelectedImageIndexer.Key;
            } 

            set {
                if (SelectedImageIndexer.Key != value) {
                    SelectedImageIndexer.Key = value; 

                    if (String.IsNullOrEmpty(value) || value.Equals(SR.GetString(SR.toStringNone))) { 
                        SelectedImageIndex = (ImageList != null) ? 0 : -1; 
                    }
                    if (IsHandleCreated) { 
                        RecreateHandle();
                    }
                }
            } 
        }
 
        ///  
        /// 
        ///     The currently selected tree node, or null if nothing is selected. 
        /// 
        [
        SRCategory(SR.CatAppearance),
        Browsable(false), 
        DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden),
        SRDescription(SR.TreeViewSelectedNodeDescr) 
        ] 
        public TreeNode SelectedNode {
            get { 
                if (IsHandleCreated) {
                    Debug.Assert(selectedNode == null || selectedNode.TreeView != this, "handle is created, but we're still caching selectedNode");
                    IntPtr hItem = SendMessage(NativeMethods.TVM_GETNEXTITEM, NativeMethods.TVGN_CARET, 0);
                    if (hItem == IntPtr.Zero) 
                        return null;
                    return NodeFromHandle(hItem); 
                } 
                else if (selectedNode != null && selectedNode.TreeView == this) {
                    return selectedNode; 
                }
                else {
                    return null;
                } 
            }
            set { 
                if (IsHandleCreated && (value == null || value.TreeView == this)) { 
                    // This class invariant is not quite correct -- if the selected node does not belong to this Treeview,
                    // selectedNode != null even though the handle is created.  We will call set_SelectedNode 
                    // to inform the handle that the selected node has been added to the TreeView.
                    Debug.Assert(selectedNode == null || selectedNode.TreeView != this, "handle is created, but we're still caching selectedNode");

                    IntPtr hnode = (value == null ? IntPtr.Zero : value.Handle); 
                    SendMessage(NativeMethods.TVM_SELECTITEM, NativeMethods.TVGN_CARET, hnode);
                    selectedNode = null; 
                } 
                else {
                    selectedNode = value; 
                }
            }
        }
 
        /// 
        ///  
        ///     The ShowLines property determines if lines are drawn between 
        ///     nodes in the tree view.
        ///  
        [
        SRCategory(SR.CatBehavior),
        DefaultValue(true),
        SRDescription(SR.TreeViewShowLinesDescr) 
        ]
        public bool ShowLines { 
            get { 
                return treeViewState[TREEVIEWSTATE_showLines];
            } 
            set {
                if (ShowLines != value) {
                    treeViewState[TREEVIEWSTATE_showLines] = value;
                    if (IsHandleCreated) { 
                        UpdateStyles();
                    } 
                } 
            }
        } 

        /// 
        /// 
        ///     The ShowLines property determines whether or not the tooltips willbe displayed on the nodes 
        /// 
        [ 
        SRCategory(SR.CatBehavior), 
        DefaultValue(false),
        SRDescription(SR.TreeViewShowShowNodeToolTipsDescr) 
        ]
        public bool ShowNodeToolTips {
            get {
                return treeViewState[TREEVIEWSTATE_showNodeToolTips]; 
            }
            set { 
                if (ShowNodeToolTips != value) { 
                    treeViewState[TREEVIEWSTATE_showNodeToolTips] = value;
                    if (ShowNodeToolTips) 
                        RecreateHandle();
                }
            }
        } 

        ///  
        ///  
        ///     The ShowPlusMinus property determines if the "plus/minus"
        ///     expand button is shown next to tree nodes that have children. 
        /// 
        [
        SRCategory(SR.CatBehavior),
        DefaultValue(true), 
        SRDescription(SR.TreeViewShowPlusMinusDescr)
        ] 
        public bool ShowPlusMinus { 
            get {
                return treeViewState[TREEVIEWSTATE_showPlusMinus]; 
            }
            set {
                if (ShowPlusMinus != value) {
                    treeViewState[TREEVIEWSTATE_showPlusMinus] = value; 
                    if (IsHandleCreated) {
                        UpdateStyles(); 
                    } 
                }
            } 
        }

        /// 
        ///  
        ///     Determines if lines are draw between nodes at the root of
        ///     the tree view. 
        ///  
        [
        SRCategory(SR.CatBehavior), 
        DefaultValue(true),
        SRDescription(SR.TreeViewShowRootLinesDescr)
        ]
        public bool ShowRootLines { 
            get { return treeViewState[TREEVIEWSTATE_showRootLines];}
            set { 
                if (ShowRootLines != value) { 
                    treeViewState[TREEVIEWSTATE_showRootLines] = value;
                    if (IsHandleCreated) { 
                        UpdateStyles();
                    }
                }
            } 
        }
 
        ///  
        /// 
        ///     The Sorted property determines if nodes in the tree view are sorted. 
        /// 
        [
        SRCategory(SR.CatBehavior),
        DefaultValue(false), 
        SRDescription(SR.TreeViewSortedDescr),
        Browsable(false), EditorBrowsable(EditorBrowsableState.Never) 
        ] 
        public bool Sorted {
            get { 
                return treeViewState[TREEVIEWSTATE_sorted];
            }
            set {
                if (Sorted != value) { 
                    treeViewState[TREEVIEWSTATE_sorted] = value;
                    if (Sorted && TreeViewNodeSorter == null && Nodes.Count >= 1) { 
                        RefreshNodes(); 
                    }
                } 
            }
        }

 
        /// 
        ///  
        ///     The sorting comparer for this TreeView. 
        /// 
        [ 
        SRCategory(SR.CatBehavior),
        Browsable(false),
        DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden),
        SRDescription(SR.TreeViewNodeSorterDescr) 
        ]
        public IComparer TreeViewNodeSorter { 
            get { 
                return treeViewNodeSorter;
            } 
            set {
                if (treeViewNodeSorter != value) {
                    treeViewNodeSorter = value;
                    if (value != null) { 
                        Sort();
                    } 
                } 
            }
        } 

        /// 
        /// 
        ///    [To be supplied.] 
        /// 
        [Browsable(false), EditorBrowsable(EditorBrowsableState.Never), Bindable(false)] 
        public override string Text { 
            get {
                return base.Text; 
            }
            set {
                base.Text = value;
            } 
        }
 
        ///  
        /// 
        [Browsable(false), EditorBrowsable(EditorBrowsableState.Never)] 
        new public event EventHandler TextChanged {
            add {
                base.TextChanged += value;
            } 
            remove {
                base.TextChanged -= value; 
            } 
        }
 
        /// 
        /// 
        ///     The first visible node in the TreeView. Initially
        ///     the first root node is at the top of the TreeView, but if the 
        ///     contents have been scrolled another node may be at the top.
        ///  
        [ 
        SRCategory(SR.CatAppearance),
        Browsable(false), 
        DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden),
        SRDescription(SR.TreeViewTopNodeDescr)
        ]
        public TreeNode TopNode { 
            get {
                if (IsHandleCreated) { 
                    IntPtr hitem = SendMessage(NativeMethods.TVM_GETNEXTITEM, NativeMethods.TVGN_FIRSTVISIBLE, 0); 
                    return(hitem == IntPtr.Zero ? null : NodeFromHandle(hitem));
                } 
                return topNode;
            }
            set {
                if (IsHandleCreated && (value == null || value.TreeView == this)) { 
                    // This class invariant is not quite correct -- if the selected node does not belong to this Treeview,
                    // selectedNode != null even though the handle is created.  We will call set_SelectedNode 
                    // to inform the handle that the selected node has been added to the TreeView. 
                    Debug.Assert(topNode == null || topNode.TreeView != this, "handle is created, but we're still caching selectedNode");
 
                    IntPtr hnode = (value == null ? IntPtr.Zero : value.Handle);
                    SendMessage(NativeMethods.TVM_SELECTITEM, NativeMethods.TVGN_FIRSTVISIBLE, hnode);
                    topNode = null;
                } 
                else {
                    topNode = value; 
                } 

            } 
        }

        /// 
        ///  
        ///     The count of fully visible nodes in the tree view.  This number
        ///     may be greater than the number of nodes in the control. 
        ///     The control calculates this value by dividing the height of the 
        ///     client window by the height of an item
        ///  
        [
        SRCategory(SR.CatAppearance),
        Browsable(false),
        DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden), 
        SRDescription(SR.TreeViewVisibleCountDescr)
        ] 
        public int VisibleCount { 
            get {
                if (IsHandleCreated) 
                    return unchecked( (int) (long)SendMessage(NativeMethods.TVM_GETVISIBLECOUNT, 0, 0));

                return 0;
            } 
        }
 
 
        /// 
        ///  
        ///    [To be supplied.]
        /// 
        [SRCategory(SR.CatBehavior), SRDescription(SR.TreeViewBeforeEditDescr)]
        public event NodeLabelEditEventHandler BeforeLabelEdit { 
            add {
                onBeforeLabelEdit += value; 
            } 
            remove {
                onBeforeLabelEdit -= value; 
            }
        }

 
        /// 
        ///  
        ///    [To be supplied.] 
        /// 
        [SRCategory(SR.CatBehavior), SRDescription(SR.TreeViewAfterEditDescr)] 
        public event NodeLabelEditEventHandler AfterLabelEdit {
            add {
                onAfterLabelEdit += value;
            } 
            remove {
                onAfterLabelEdit -= value; 
            } 
        }
 

        /// 
        /// 
        ///    [To be supplied.] 
        /// 
        [SRCategory(SR.CatBehavior), SRDescription(SR.TreeViewBeforeCheckDescr)] 
        public event TreeViewCancelEventHandler BeforeCheck { 
            add {
                onBeforeCheck += value; 
            }
            remove {
                onBeforeCheck -= value;
            } 
        }
 
 
        /// 
        ///  
        ///    [To be supplied.]
        /// 
        [SRCategory(SR.CatBehavior), SRDescription(SR.TreeViewAfterCheckDescr)]
        public event TreeViewEventHandler AfterCheck { 
            add {
                onAfterCheck += value; 
            } 
            remove {
                onAfterCheck -= value; 
            }
        }

 
        /// 
        ///  
        ///    [To be supplied.] 
        /// 
        [SRCategory(SR.CatBehavior), SRDescription(SR.TreeViewBeforeCollapseDescr)] 
        public event TreeViewCancelEventHandler BeforeCollapse {
            add {
                onBeforeCollapse += value;
            } 
            remove {
                onBeforeCollapse -= value; 
            } 
        }
 

        /// 
        /// 
        ///    [To be supplied.] 
        /// 
        [SRCategory(SR.CatBehavior), SRDescription(SR.TreeViewAfterCollapseDescr)] 
        public event TreeViewEventHandler AfterCollapse { 
            add {
                onAfterCollapse += value; 
            }
            remove {
                onAfterCollapse -= value;
            } 
        }
 
 
        /// 
        ///  
        ///    [To be supplied.]
        /// 
        [SRCategory(SR.CatBehavior), SRDescription(SR.TreeViewBeforeExpandDescr)]
        public event TreeViewCancelEventHandler BeforeExpand { 
            add {
                onBeforeExpand += value; 
            } 
            remove {
                onBeforeExpand -= value; 
            }
        }

 
        /// 
        ///  
        ///    [To be supplied.] 
        /// 
        [SRCategory(SR.CatBehavior), SRDescription(SR.TreeViewAfterExpandDescr)] 
        public event TreeViewEventHandler AfterExpand {
            add {
                onAfterExpand += value;
            } 
            remove {
                onAfterExpand -= value; 
            } 
        }
 
        /// 
        /// 
        ///    Fires when a TreeView node needs to be drawn.
        ///  
        [SRCategory(SR.CatBehavior), SRDescription(SR.TreeViewDrawNodeEventDescr)]
        public event DrawTreeNodeEventHandler DrawNode { 
            add { 
                onDrawNode += value;
            } 
            remove {
                onDrawNode -= value;
            }
        } 

        ///  
        ///  
        ///    [To be supplied.]
        ///  
        [SRCategory(SR.CatAction), SRDescription(SR.ListViewItemDragDescr)]
        public event ItemDragEventHandler ItemDrag {
            add {
                onItemDrag += value; 
            }
            remove { 
                onItemDrag -= value; 
            }
        } 

        /// 
        /// 
        ///    [To be supplied.] 
        /// 
        [SRCategory(SR.CatAction), SRDescription(SR.TreeViewNodeMouseHoverDescr)] 
        public event TreeNodeMouseHoverEventHandler NodeMouseHover  { 
            add {
                onNodeMouseHover += value; 
            }
            remove {
                onNodeMouseHover -= value;
            } 
        }
 
 

        ///  
        /// 
        ///    [To be supplied.]
        /// 
        [SRCategory(SR.CatBehavior), SRDescription(SR.TreeViewBeforeSelectDescr)] 
        public event TreeViewCancelEventHandler BeforeSelect {
            add { 
                onBeforeSelect += value; 
            }
            remove { 
                onBeforeSelect -= value;
            }
        }
 

        ///  
        ///  
        ///    [To be supplied.]
        ///  
        [SRCategory(SR.CatBehavior), SRDescription(SR.TreeViewAfterSelectDescr)]
        public event TreeViewEventHandler AfterSelect {
            add {
                onAfterSelect += value; 
            }
            remove { 
                onAfterSelect -= value; 
            }
        } 

        /// 
        /// 
        ///     TreeView Onpaint. 
        /// 
        ///  
        [Browsable(false), EditorBrowsable(EditorBrowsableState.Never)] 
        public new event PaintEventHandler Paint {
            add { 
                base.Paint += value;
            }
            remove {
                base.Paint -= value; 
            }
        } 
 
        /// 
        ///  
        ///    [To be supplied.]
        /// 
        [SRCategory(SR.CatBehavior), SRDescription(SR.TreeViewNodeMouseClickDescr)]
        public event TreeNodeMouseClickEventHandler NodeMouseClick { 
            add {
                onNodeMouseClick += value; 
            } 
            remove {
                onNodeMouseClick -= value; 
            }
        }

        ///  
        /// 
        ///    [To be supplied.] 
        ///  
        [SRCategory(SR.CatBehavior), SRDescription(SR.TreeViewNodeMouseDoubleClickDescr)]
        public event TreeNodeMouseClickEventHandler NodeMouseDoubleClick { 
            add {
                onNodeMouseDoubleClick += value;
            }
            remove { 
                onNodeMouseDoubleClick -= value;
            } 
        } 

        ///  
        /// 
        ///    [To be supplied.]
        /// 
        [SRCategory(SR.CatPropertyChanged), SRDescription(SR.ControlOnRightToLeftLayoutChangedDescr)] 
        public event EventHandler RightToLeftLayoutChanged {
            add { 
                onRightToLeftLayoutChanged += value; 
            }
            remove { 
                onRightToLeftLayoutChanged -= value;
            }
        }
 

        ///  
        ///  
        ///     Disables redrawing of the tree view. A call to beginUpdate() must be
        ///     balanced by a following call to endUpdate(). Following a call to 
        ///     beginUpdate(), any redrawing caused by operations performed on the
        ///     tree view is deferred until the call to endUpdate().
        /// 
        public void BeginUpdate() { 
            BeginUpdateInternal();
        } 
 
        /// 
        ///  
        ///     Collapses all nodes at the root level.
        /// 
        public void CollapseAll() {
            root.Collapse(); 
        }
 
        ///  
        /// 
        ///  
        /// 
        protected override void CreateHandle() {
            if (!RecreatingHandle) {
                IntPtr userCookie = UnsafeNativeMethods.ThemingScope.Activate(); 
                try {
                    NativeMethods.INITCOMMONCONTROLSEX icc = new NativeMethods.INITCOMMONCONTROLSEX(); 
                    icc.dwICC = NativeMethods.ICC_TREEVIEW_CLASSES; 
                    SafeNativeMethods.InitCommonControlsEx(icc);
                } finally { 
                    UnsafeNativeMethods.ThemingScope.Deactivate(userCookie);
                }
            }
            base.CreateHandle(); 
        }
 
        ///  
        /// 
        ///     Resets the imageList to null.  We wire this method up to the imageList's 
        ///     Dispose event, so that we don't hang onto an imageList that's gone away.
        /// 
        /// 
        private void DetachImageList(object sender, EventArgs e) { 
            ImageList = null;
        } 
 
        /// 
        ///  
        ///     Resets the stateimageList to null.  We wire this method up to the stateimageList's
        ///     Dispose event, so that we don't hang onto an stateimageList that's gone away.
        /// 
        ///  
        private void DetachStateImageList(object sender, EventArgs e) {
            internalStateImageList = null; 
            StateImageList = null; 

        } 

        /// 
        /// 
        ///  
        /// 
        protected override void Dispose(bool disposing) { 
            if (disposing) { 

                foreach (TreeNode node in Nodes) { 
                    node.ContextMenu = null;
                }

                // 
                lock(this) {
                    DetachImageListHandlers(); 
                    imageList = null; 
                    DetachStateImageListHandlers();
                    stateImageList = null; 
                 }

            }
 
            base.Dispose(disposing);
        } 
 
        /// 
        ///  
        ///     Reenables redrawing of the tree view. A call to beginUpdate() must be
        ///     balanced by a following call to endUpdate(). Following a call to
        ///     beginUpdate(), any redrawing caused by operations performed on the
        ///     combo box is deferred until the call to endUpdate(). 
        /// 
        public void EndUpdate() { 
            EndUpdateInternal(); 
        }
 
        /// 
        /// 
        ///     Expands all nodes at the root level.
        ///  
        public void ExpandAll() {
            root.ExpandAll(); 
        } 

        ///  
        /// 
        ///     Forces the TreeView to recalculate all its nodes widths so that it updates the
        ///     scrollbars as appropriate.
        ///  
        /// 
        internal void ForceScrollbarUpdate(bool delayed) { 
 
            // ForceScrollbarUpdate call WM_SETREDRAW( FALSE ) followed by WM_SETREDRAW( TRUE )
            // So if TreeView.BeginUpdate is called 
            // ForceScrollbarUpdate effectively causes tree view to ignore BeginUpdate and cause control to update on every change.
            // So gaurd against this scenario by using the new internal method on Control.
            if (!IsUpdating())
            { 
                if (IsHandleCreated) {
                    SendMessage(NativeMethods.WM_SETREDRAW, 0, 0); 
                    if (delayed) 
                        UnsafeNativeMethods.PostMessage(new HandleRef(this, Handle), NativeMethods.WM_SETREDRAW, (IntPtr)1, IntPtr.Zero);
                    else 
                        SendMessage(NativeMethods.WM_SETREDRAW, 1, 0);
                }
            }
        } 

        ///  
        ///  
        ///     Called by ToolTip to poke in that Tooltip into this ComCtl so that the Native ChildToolTip is not exposed.
        ///  
        /// 
        internal void SetToolTip(ToolTip toolTip, string toolTipText) {
            if (toolTip != null) {
                UnsafeNativeMethods.SendMessage(new HandleRef(toolTip, toolTip.Handle), NativeMethods.TTM_SETMAXTIPWIDTH, 0, SystemInformation.MaxWindowTrackSize.Width); 
                UnsafeNativeMethods.SendMessage(new HandleRef(this, this.Handle), NativeMethods.TVM_SETTOOLTIPS, new HandleRef(toolTip, toolTip.Handle), 0);
                controlToolTipText = toolTipText; 
            } 
        }
 

        /// 
        /// 
        ///     Gives the information about which part of the treeNode is at the given point. 
        /// 
        public TreeViewHitTestInfo HitTest(Point pt) { 
            return HitTest(pt.X, pt.Y); 
        }
 
        /// 
        /// 
        ///     Gives the information about which part of the treeNode is at the given x, y.
        ///  
        public TreeViewHitTestInfo HitTest(int x, int y) {
            NativeMethods.TV_HITTESTINFO tvhi = new NativeMethods.TV_HITTESTINFO(); 
            tvhi.pt_x = x; 
            tvhi.pt_y = y;
            IntPtr hnode = UnsafeNativeMethods.SendMessage(new HandleRef(this, Handle), NativeMethods.TVM_HITTEST, 0, tvhi); 
            TreeNode node = (hnode == IntPtr.Zero ? null : NodeFromHandle(hnode));
            TreeViewHitTestLocations loc = (TreeViewHitTestLocations)tvhi.flags;
            return (new TreeViewHitTestInfo(node, loc));
        } 

        ///  
        ///  
        ///     Defined so that a  tree node can use it
        /// 
        /// 
        /// 

        internal bool TreeViewBeforeCheck(TreeNode node, TreeViewAction actionTaken) { 
            TreeViewCancelEventArgs tvce = new TreeViewCancelEventArgs(node, false, actionTaken);
            OnBeforeCheck(tvce); 
            return (tvce.Cancel); 
        }
 
        internal void TreeViewAfterCheck(TreeNode node, TreeViewAction actionTaken) {
            OnAfterCheck(new TreeViewEventArgs(node, actionTaken));
        }
 

        ///  
        ///  
        ///     Returns count of nodes at root, optionally including all subtrees.
        ///  
        public int GetNodeCount(bool includeSubTrees) {
            return root.GetNodeCount(includeSubTrees);
        }
 
        /// 
        ///  
        ///     Returns the TreeNode at the given location in tree view coordinates. 
        /// 
        public TreeNode GetNodeAt(Point pt) { 
            return GetNodeAt(pt.X, pt.Y);
        }

        ///  
        /// 
        ///     Returns the TreeNode at the given location in tree view coordinates. 
        ///  
        public TreeNode GetNodeAt(int x, int y) {
            NativeMethods.TV_HITTESTINFO tvhi = new NativeMethods.TV_HITTESTINFO(); 

            tvhi.pt_x = x;
            tvhi.pt_y = y;
 
            IntPtr hnode = UnsafeNativeMethods.SendMessage(new HandleRef(this, Handle), NativeMethods.TVM_HITTEST, 0, tvhi);
 
            return(hnode == IntPtr.Zero ? null : NodeFromHandle(hnode)); 
        }
 
        private void ImageListRecreateHandle(object sender, EventArgs e) {
            if (IsHandleCreated) {
                IntPtr handle = (ImageList == null) ? IntPtr.Zero : ImageList.Handle;
                SendMessage(NativeMethods.TVM_SETIMAGELIST, 0, handle); 
            }
        } 
 
        private void UpdateImagesRecursive ( TreeNode node )
        { 
            node.UpdateImage();
            // VSWhidbey 208200: Iterate only through the Nodes collection rather than the
            // array since an item might have been removed from the collection, and
            // correspondingly "removed" from the array, but still exist in the array 
            // since the array isn't actually re-dimensioned down to a smaller size.
            foreach (TreeNode child in node.Nodes) { 
                UpdateImagesRecursive(child); 
            }
        } 

        private void ImageListChangedHandle(object sender, EventArgs e) {
            if ((null != sender) && (sender == imageList) && IsHandleCreated) {
                BeginUpdate(); 
                foreach (TreeNode node in Nodes) {
                    UpdateImagesRecursive(node); 
                } 
                EndUpdate();
            } 
        }

        private void StateImageListRecreateHandle(object sender, EventArgs e) {
            if (IsHandleCreated) { 
                IntPtr handle = IntPtr.Zero;
                if (internalStateImageList != null) { 
                    handle = internalStateImageList.Handle; 
                }
                SendMessage(NativeMethods.TVM_SETIMAGELIST, NativeMethods.TVSIL_STATE, handle); 
            }
        }

        private void StateImageListChangedHandle(object sender, EventArgs e) { 
            if ((null != sender) && (sender == stateImageList) && IsHandleCreated) {
                // Since the native treeview requires the state imagelist to be 1-indexed we need to 
                // re add the images if the original collection had changed. 
                if (stateImageList != null && stateImageList.Images.Count > 0) {
                    Image[] images = new Image[stateImageList.Images.Count + 1]; 
                    images[0] = stateImageList.Images[0];
                    for (int i = 1;  i <= stateImageList.Images.Count ; i++) {
                        images[i] = stateImageList.Images[i -1];
                    } 

 
                    if (internalStateImageList != null) 
                    {
                        internalStateImageList.Images.Clear(); 
                        internalStateImageList.Images.AddRange(images);
                    }
                    else
                    { 
                        internalStateImageList = new ImageList();
                        internalStateImageList.Images.AddRange(images); 
                    } 

                    Debug.Assert(internalStateImageList != null, "Why are changing images when the Imagelist is null?"); 
                    if (internalStateImageList != null)
                    {
                        SendMessage(NativeMethods.TVM_SETIMAGELIST, NativeMethods.TVSIL_STATE, internalStateImageList.Handle);
                    } 
                }
                else //stateImageList == null || stateImageList.Images.Count = 0; 
                { 
                    UpdateCheckedState(root, true);
                } 
            }
        }

        ///  
        /// 
        ///  
        ///     
        ///       Overridden to handle RETURN key.
        ///     
        /// 
        protected override bool IsInputKey(Keys keyData) {
            // If in edit mode, treat Return as an input key, so the form doesn't grab it
            // and treat it as clicking the Form.AcceptButton.  Similarly for Escape 
            // and Form.CancelButton.
            if (editNode != null && (keyData & Keys.Alt) == 0) { 
                switch (keyData & Keys.KeyCode) { 
                    case Keys.Return:
                    case Keys.Escape: 
                    case Keys.PageUp:
                    case Keys.PageDown:
                    case Keys.Home:
                    case Keys.End: 
                        return true;
                } 
            } 
            return base.IsInputKey(keyData);
        } 

        /// 
        /// 
        ///    Note this can be null - particularly if any windows messages get generated during 
        ///    the insertion of a tree node (TVM_INSERTITEM)
        ///  
        ///  
        internal TreeNode NodeFromHandle(IntPtr handle) {
            TreeNode node = (TreeNode)nodeTable[handle]; 

            return node;
        }
 
        /// 
        ///  
        /// Fires the DrawNode event. 
        /// 
        protected virtual void OnDrawNode(DrawTreeNodeEventArgs e) { 
        if (onDrawNode != null) onDrawNode(this, e);
    }

        ///  
        /// 
        ///  
        ///  
        protected override void OnHandleCreated(EventArgs e) {
 
            TreeNode savedSelectedNode = this.selectedNode;
            this.selectedNode = null;

            base.OnHandleCreated(e); 

            //ComCtl 5 has some bug fixes that, to enable, require us to send the control 
            //a CCM_SETVERSION with 5 as the version. The one we want in particular is 
            //the fix for the node clipping issue when a font is set by means of CDRF_NEWFONT.
            //The fix is not perfect, but the behavior is better than before. 
            int version = unchecked((int)(long)SendMessage(NativeMethods.CCM_GETVERSION, 0, 0));
            if (version < 5) {
                SendMessage(NativeMethods.CCM_SETVERSION, 5, 0);
            } 

            // Workaround for problem in TreeView where it doesn't recognize the TVS_CHECKBOXES 
            // style if it is set before the window is created.  To get around the problem, 
            // we set it here after the window is created, and we make sure we don't set it
            // in getCreateParams so that this will actually change the value of the bit. 
            // This seems to make the Treeview happy.
            if (CheckBoxes) {
                int style = unchecked((int)(UnsafeNativeMethods.GetWindowLong(new HandleRef(this, Handle), NativeMethods.GWL_STYLE)));
                style |= NativeMethods.TVS_CHECKBOXES; 
                UnsafeNativeMethods.SetWindowLong(new HandleRef(this, Handle), NativeMethods.GWL_STYLE, new HandleRef(null, (IntPtr)style));
            } 
 
            if (ShowNodeToolTips && !DesignMode) {
                int style = unchecked((int)(UnsafeNativeMethods.GetWindowLong(new HandleRef(this, Handle), NativeMethods.GWL_STYLE))); 
                style |= NativeMethods.TVS_INFOTIP;
                UnsafeNativeMethods.SetWindowLong(new HandleRef(this, Handle), NativeMethods.GWL_STYLE, new HandleRef(null, (IntPtr)style));
            }
 
            Color c;
            c = BackColor; 
            if (c != SystemColors.Window) 
                SendMessage(NativeMethods.TVM_SETBKCOLOR, 0, ColorTranslator.ToWin32(c));
            c = ForeColor; 

            if (c != SystemColors.WindowText)
                SendMessage(NativeMethods.TVM_SETTEXTCOLOR, 0, ColorTranslator.ToWin32(c));
 
            /// put the linecolor into the native control only if Set ...
            if (lineColor != Color.Empty) { 
                SendMessage(NativeMethods.TVM_SETLINECOLOR, 0, ColorTranslator.ToWin32(lineColor)); 
            }
 


            if (imageList != null)
                SendMessage(NativeMethods.TVM_SETIMAGELIST, 0, imageList.Handle); 

            if (stateImageList != null && stateImageList.Images.Count > 0) 
            { 
                Image[] images = new Image[stateImageList.Images.Count + 1];
                images[0] = stateImageList.Images[0]; 
                for (int i = 1;  i <= stateImageList.Images.Count ; i++) {
                    images[i] = stateImageList.Images[i -1];
                }
                internalStateImageList = new ImageList(); 
                internalStateImageList.Images.AddRange(images);
                SendMessage(NativeMethods.TVM_SETIMAGELIST, NativeMethods.TVSIL_STATE, internalStateImageList.Handle); 
            } 

 
            if (indent != -1) {
                SendMessage(NativeMethods.TVM_SETINDENT, indent, 0);
            }
 
            if (itemHeight != -1) {
                SendMessage(NativeMethods.TVM_SETITEMHEIGHT, ItemHeight, 0); 
            } 

            // Fix for bug 331158.  Essentially we are setting the width to be infinite so that the 
            // TreeView never thinks it needs a scrollbar when the first node is created
            // during the first handle creation.
            //
            // This is set back to the oldSize after the Realize method. 
            int oldSize = 0;
            try 
            { 

                treeViewState[TREEVIEWSTATE_stopResizeWindowMsgs] = true; 
                oldSize = this.Width;
                int flags = NativeMethods.SWP_NOZORDER | NativeMethods.SWP_NOACTIVATE | NativeMethods.SWP_NOMOVE;
                SafeNativeMethods.SetWindowPos(new HandleRef(this, this.Handle), NativeMethods.NullHandleRef, this.Left, this.Top, Int32.MaxValue, this.Height, flags);
 
                root.Realize(false);
 
                if (oldSize != 0) 
                {
                    SafeNativeMethods.SetWindowPos(new HandleRef(this, this.Handle), NativeMethods.NullHandleRef, this.Left, this.Top, oldSize, this.Height, flags); 
                }
            }
            finally
            { 
                treeViewState[TREEVIEWSTATE_stopResizeWindowMsgs] = false;
            } 
 
            SelectedNode = savedSelectedNode;
        } 

        /// 
        /// 
        ///  
        /// 
        protected override void OnHandleDestroyed(EventArgs e) { 
            selectedNode = SelectedNode; 
            base.OnHandleDestroyed(e);
        } 


        /// 
        ///  
        ///  We keep track of if we've hovered already so we don't fire multiple hover events
        ///  
        ///  
        protected override void OnMouseLeave(EventArgs e) {
            hoveredAlready = false; 
            base.OnMouseLeave(e);
        }

        ///  
        /// 
        ///     In order for the MouseHover event to fire for each item in a TreeView, 
        ///     the node the mouse is hovering over is found. Each time a new node is hovered 
        ///     over a new event is raised.
        ///  
        protected override void OnMouseHover(EventArgs e)  {

            /// Hover events need to be caught for each node
            /// within the TreeView so the appropriate 
            /// NodeHovered event can be raised.
 
            NativeMethods.TV_HITTESTINFO tvhip = new NativeMethods.TV_HITTESTINFO(); 
            Point pos = Cursor.Position;
            pos = PointToClientInternal(pos); 
            tvhip.pt_x = pos.X;
            tvhip.pt_y = pos.Y;
            IntPtr hnode = UnsafeNativeMethods.SendMessage(new HandleRef(this, Handle), NativeMethods.TVM_HITTEST, 0, tvhip);
 
            if (hnode != IntPtr.Zero && ((tvhip.flags & NativeMethods.TVHT_ONITEM) != 0)) {
                TreeNode tn = NodeFromHandle(hnode); 
                if (tn != prevHoveredNode && tn != null) { 
                    OnNodeMouseHover( new TreeNodeMouseHoverEventArgs(tn));
                    prevHoveredNode = tn; 
                }
            }

            if (!hoveredAlready) { 
                base.OnMouseHover(e);
                hoveredAlready = true; 
            } 

            ResetMouseEventArgs(); 

        }

        ///  
        /// 
        ///     Fires the beforeLabelEdit event. 
        ///  
        protected virtual void OnBeforeLabelEdit(NodeLabelEditEventArgs e) {
            if (onBeforeLabelEdit != null) onBeforeLabelEdit(this, e); 
        }

        /// 
        ///  
        ///     Fires the afterLabelEdit event.
        ///  
        protected virtual void OnAfterLabelEdit(NodeLabelEditEventArgs e) { 
            if (onAfterLabelEdit != null) onAfterLabelEdit(this, e);
        } 

        /// 
        /// 
        ///     Fires the beforeCheck event. 
        /// 
        protected virtual void OnBeforeCheck(TreeViewCancelEventArgs e) { 
            if (onBeforeCheck != null) onBeforeCheck(this, e); 
        }
 
        /// 
        /// 
        ///     Fires the afterCheck event.
        ///  
        protected virtual void OnAfterCheck(TreeViewEventArgs e) {
            if (onAfterCheck != null) onAfterCheck(this, e); 
        } 

        ///  
        /// 
        ///     Fires the beforeCollapse event.
        /// 
        protected internal virtual void OnBeforeCollapse(TreeViewCancelEventArgs e) { 
            if (onBeforeCollapse != null) onBeforeCollapse(this, e);
        } 
 
        /// 
        ///  
        ///     Fires the afterCollapse event.
        /// 
        protected internal virtual void OnAfterCollapse(TreeViewEventArgs e) {
            if (onAfterCollapse != null) onAfterCollapse(this, e); 
        }
 
        ///  
        /// 
        ///     Fires the beforeExpand event. 
        /// 
        protected virtual void OnBeforeExpand(TreeViewCancelEventArgs e) {
            if (onBeforeExpand != null) onBeforeExpand(this, e);
        } 

        ///  
        ///  
        ///     Fires the afterExpand event.
        ///  
        protected virtual void OnAfterExpand(TreeViewEventArgs e) {
            if (onAfterExpand != null) onAfterExpand(this, e);
        }
 
        /// 
        ///  
        ///     Fires the ItemDrag event. 
        /// 
        protected virtual void OnItemDrag(ItemDragEventArgs e) { 
            if (onItemDrag != null) onItemDrag(this, e);
        }

        ///  
        /// 
        ///     Fires the NodeMouseHover event. 
        ///  
        protected virtual void OnNodeMouseHover(TreeNodeMouseHoverEventArgs e) {
            if (onNodeMouseHover != null) onNodeMouseHover(this, e); 
        }

        /// 
        ///  
        ///     Fires the beforeSelect event.
        ///  
        protected virtual void OnBeforeSelect(TreeViewCancelEventArgs e) { 
            if (onBeforeSelect != null) onBeforeSelect(this, e);
        } 

        /// 
        /// 
        ///     Fires the afterSelect event. 
        /// 
        protected virtual void OnAfterSelect(TreeViewEventArgs e) { 
            if (onAfterSelect != null) onAfterSelect(this, e); 
        }
 
        /// 
        /// 
        ///     Fires the onNodeMouseClick event.
        ///  
        protected virtual void OnNodeMouseClick(TreeNodeMouseClickEventArgs e) {
            if (onNodeMouseClick != null) onNodeMouseClick(this, e); 
        } 

        ///  
        /// 
        ///     Fires the onNodeMouseDoubleClick event.
        /// 
        protected virtual void OnNodeMouseDoubleClick(TreeNodeMouseClickEventArgs e) { 
            if (onNodeMouseDoubleClick != null) onNodeMouseDoubleClick(this, e);
        } 
 
        /// 
        ///  
        ///     Handles the OnBeforeCheck / OnAfterCheck for keyboard clicks
        /// 
        /// 
        protected override void OnKeyDown(KeyEventArgs e) { 
            base.OnKeyDown(e);
            if (e.Handled) return; 
            // if it's a space, send the check notifications and toggle the checkbox if we're not 
            // cancelled.
            if (CheckBoxes && (e.KeyData & Keys.KeyCode) == Keys.Space) { 
                TreeNode node = this.SelectedNode;
                if (node != null) {
                    bool eventReturn = TreeViewBeforeCheck(node, TreeViewAction.ByKeyboard);
                    if (!eventReturn) { 
                        node.CheckedInternal = !node.CheckedInternal;
                        TreeViewAfterCheck(node, TreeViewAction.ByKeyboard); 
                    } 
                    e.Handled = true;
                    return; 
                }
            }
        }
 
        /// 
        ///  
        ///     Handles the OnBeforeCheck / OnAfterCheck for keyboard clicks 
        /// 
        ///  
        protected override void OnKeyUp(KeyEventArgs e) {
            base.OnKeyUp(e);
            if (e.Handled) return;
            // eat the space key 
            if ((e.KeyData & Keys.KeyCode) == Keys.Space) {
                e.Handled = true; 
                return; 
            }
        } 

        /// 
        /// 
        ///     Handles the OnBeforeCheck / OnAfterCheck for keyboard clicks 
        /// 
        ///  
        protected override void OnKeyPress(KeyPressEventArgs e) { 
            base.OnKeyPress(e);
            if (e.Handled) return; 
            // eat the space key
            if (e.KeyChar == ' ') e.Handled = true;
        }
 

        ///  
        ///  
        ///    [To be supplied.]
        ///  
        [EditorBrowsable(EditorBrowsableState.Advanced)]
        protected virtual void OnRightToLeftLayoutChanged(EventArgs e) {
            if (GetAnyDisposingInHierarchy()) {
                return; 
            }
 
            if (RightToLeft == RightToLeft.Yes) { 
                RecreateHandle();
            } 

            if (onRightToLeftLayoutChanged != null) {
                 onRightToLeftLayoutChanged(this, e);
            } 
        }
 
 

        // Refresh the nodes by clearing the tree and adding the nodes back again 
        //
        private void RefreshNodes() {
            TreeNode[] nodes = new TreeNode[Nodes.Count];
            Nodes.CopyTo(nodes, 0); 

            Nodes.Clear(); 
            Nodes.AddRange(nodes); 
        }
 
        /// 
        /// 
        ///     This resets the indentation to the system default.
        ///  
        private void ResetIndent() {
            indent = -1; 
            // is this overkill? 
            RecreateHandle();
        } 

        /// 
        /// 
        ///     This resets the item height to the system default. 
        /// 
        private void ResetItemHeight() { 
            itemHeight = -1; 
            RecreateHandle();
        } 

        /// 
        /// 
        ///     Retrieves true if the indent should be persisted in code gen. 
        /// 
        private bool ShouldSerializeIndent() { 
            return(indent != -1); 
        }
 
        /// 
        /// 
        ///     Retrieves true if the itemHeight should be persisted in code gen.
        ///  
        private bool ShouldSerializeItemHeight() {
            return(itemHeight != -1); 
        } 

        private bool ShouldSerializeSelectedImageIndex() { 
             if (imageList != null) {
                 return (SelectedImageIndex != 0);
             }
             return (SelectedImageIndex != -1); 
         }
 
 
         private bool ShouldSerializeImageIndex() {
             if (imageList != null) { 
                 return (ImageIndex != 0);
             }
             return (ImageIndex != -1);
         } 

 
        ///  
        /// 
        ///      Updated the sorted order 
        /// 
        public void Sort() {
            Sorted = true;
            RefreshNodes(); 
        }
 
 
        /// 
        ///  
        ///     Returns a string representation for this control.
        /// 
        /// 
        public override string ToString() { 

            string s = base.ToString(); 
            if (Nodes != null) { 
                s += ", Nodes.Count: " + Nodes.Count.ToString(CultureInfo.CurrentCulture);
                if (Nodes.Count > 0) 
                    s += ", Nodes[0]: " + Nodes[0].ToString();
            }
            return s;
        } 

        private unsafe void TvnBeginDrag(MouseButtons buttons, NativeMethods.NMTREEVIEW* nmtv) { 
            NativeMethods.TV_ITEM item = nmtv->itemNew; 

            // Check for invalid node handle 
            if (item.hItem == IntPtr.Zero) {
                return;
            }
 
            TreeNode node = NodeFromHandle(item.hItem);
 
            OnItemDrag(new ItemDragEventArgs(buttons, node)); 
        }
 
        private unsafe IntPtr TvnExpanding(NativeMethods.NMTREEVIEW* nmtv) {
            NativeMethods.TV_ITEM item = nmtv->itemNew;

            // Check for invalid node handle 
            if (item.hItem == IntPtr.Zero) {
                return IntPtr.Zero; 
            } 

            TreeViewCancelEventArgs e = null; 
            if ((item.state & NativeMethods.TVIS_EXPANDED) == 0) {
                e = new TreeViewCancelEventArgs(NodeFromHandle(item.hItem), false, TreeViewAction.Expand);
                OnBeforeExpand(e);
            } 
            else {
                e = new TreeViewCancelEventArgs(NodeFromHandle(item.hItem), false, TreeViewAction.Collapse); 
                OnBeforeCollapse(e); 
            }
            return (IntPtr)(e.Cancel? 1: 0); 
        }

        private unsafe void TvnExpanded(NativeMethods.NMTREEVIEW* nmtv) {
            NativeMethods.TV_ITEM item = nmtv->itemNew; 

            // Check for invalid node handle 
            if (item.hItem == IntPtr.Zero) { 
                return;
            } 

            TreeViewEventArgs e;
            TreeNode node = NodeFromHandle(item.hItem);
 
            // Note that IsExpanded is invalid for the moment, so we use item item.state to branch.
            if ((item.state & NativeMethods.TVIS_EXPANDED) == 0) { 
                e = new TreeViewEventArgs(node, TreeViewAction.Collapse); 
                OnAfterCollapse(e);
            } 
            else {
                e = new TreeViewEventArgs(node, TreeViewAction.Expand);
                OnAfterExpand(e);
            } 
        }
 
        private unsafe IntPtr TvnSelecting(NativeMethods.NMTREEVIEW* nmtv) { 
            if (treeViewState[ TREEVIEWSTATE_ignoreSelects])
            { 
                return (IntPtr)1;
            }
            // Check for invalid node handle
            if (nmtv->itemNew.hItem == IntPtr.Zero) { 
                return IntPtr.Zero;
            } 
 
            TreeNode node = NodeFromHandle(nmtv->itemNew.hItem);
 
            TreeViewAction action = TreeViewAction.Unknown;
            switch(nmtv->action) {
                case NativeMethods.TVC_BYKEYBOARD:
                    action = TreeViewAction.ByKeyboard; 
                    break;
                case NativeMethods.TVC_BYMOUSE: 
                    action = TreeViewAction.ByMouse; 
                    break;
            } 

            TreeViewCancelEventArgs e = new TreeViewCancelEventArgs(node, false, action);
            OnBeforeSelect(e);
 
            return (IntPtr)(e.Cancel? 1: 0);
        } 
 
        private unsafe void TvnSelected(NativeMethods.NMTREEVIEW* nmtv) {
            if (nodesCollectionClear) //if called thru the Clear( ) of treeNodeCollection then just return... 
            {
                return;
            }
            if (nmtv->itemNew.hItem != IntPtr.Zero) { 
                TreeViewAction action = TreeViewAction.Unknown;
                switch(nmtv->action) { 
                    case NativeMethods.TVC_BYKEYBOARD: 
                        action = TreeViewAction.ByKeyboard;
                        break; 
                    case NativeMethods.TVC_BYMOUSE:
                        action = TreeViewAction.ByMouse;
                        break;
                } 
                OnAfterSelect(new TreeViewEventArgs(NodeFromHandle(nmtv->itemNew.hItem), action));
            } 
 
            // TreeView doesn't properly revert back to the unselected image
            // if the unselected image is blank. 
            //
            NativeMethods.RECT rc = new NativeMethods.RECT();
            *((IntPtr *) &rc.left) = nmtv->itemOld.hItem;
            if (nmtv->itemOld.hItem != IntPtr.Zero) { 
                if (unchecked( (int) (long)UnsafeNativeMethods.SendMessage(new HandleRef(this, Handle), NativeMethods.TVM_GETITEMRECT, 1, ref rc)) != 0)
                    SafeNativeMethods.InvalidateRect(new HandleRef(this, Handle), ref rc, true); 
            } 
        }
 
        private IntPtr TvnBeginLabelEdit(NativeMethods.NMTVDISPINFO nmtvdi) {

            // Check for invalid node handle
            if (nmtvdi.item.hItem == IntPtr.Zero) { 
                return IntPtr.Zero;
            } 
 
            TreeNode editingNode = NodeFromHandle(nmtvdi.item.hItem);
            NodeLabelEditEventArgs e = new NodeLabelEditEventArgs(editingNode); 
            OnBeforeLabelEdit(e);
            if (!e.CancelEdit)
                editNode = editingNode;
            return (IntPtr)(e.CancelEdit ? 1 : 0); 
        }
 
        private IntPtr TvnEndLabelEdit(NativeMethods.NMTVDISPINFO nmtvdi) { 
            editNode = null;
 
            // Check for invalid node handle
            if (nmtvdi.item.hItem == IntPtr.Zero) {
                return (IntPtr)1;
            } 

            TreeNode node = NodeFromHandle(nmtvdi.item.hItem); 
            string newText = (nmtvdi.item.pszText == IntPtr.Zero ? null : Marshal.PtrToStringAuto(nmtvdi.item.pszText)); 
            NodeLabelEditEventArgs e = new NodeLabelEditEventArgs(node, newText);
            OnAfterLabelEdit(e); 
            if (newText != null && !e.CancelEdit && node != null) {
                node.text = newText;
                if (Scrollable)
                    ForceScrollbarUpdate(true); 
            }
            return (IntPtr)(e.CancelEdit ? 0 : 1); 
        } 

        internal override void UpdateStylesCore() { 
            base.UpdateStylesCore();
            if (IsHandleCreated && CheckBoxes) {
                if (StateImageList != null) {
                    // Setting the TVS_CHECKBOXES window style also causes the TreeView to display the default checkbox 
                    // images rather than the user specified StateImageList.  We send a TVM_SETIMAGELIST to restore the
                    // user's images. 
                    if (internalStateImageList != null) { 
                        SendMessage(NativeMethods.TVM_SETIMAGELIST, NativeMethods.TVSIL_STATE, internalStateImageList.Handle);
                    } 

                }
            }
        } 

        // Setting the NativeMethods.TVS_CHECKBOXES style clears the checked state 
        private void UpdateCheckedState(TreeNode node, bool update) { 
            // This looks funny, but CheckedInternal returns the cached isChecked value and the internal
            // setter will blindly issue TVM_SETITEM so this gets us back in [....]. 
            if (update)
            {
                node.CheckedInternal = node.CheckedInternal;
                for (int i = node.Nodes.Count - 1; i >= 0; i--) { 
                    UpdateCheckedState(node.Nodes[i], update);
                } 
            } 
            else
            { 
                node.CheckedInternal = false;
                for (int i = node.Nodes.Count - 1; i >= 0; i--) {
                    UpdateCheckedState(node.Nodes[i], update);
                } 
            }
        } 
 
        private void WmMouseDown(ref Message m, MouseButtons button, int clicks) {
            // Required to put the TreeView in sane-state for painting proper highlighting of selectedNodes. 
            // If the user shows the ContextMenu bu overiding the WndProc( ), then the treeview
            // goes into the weird state where the high-light gets locked to the node on which the ContextMenu was shown.
            // So we need to get the native TREEIVEW out of this weird state.
            // Refer to VSWhidbey : 249191. 
            SendMessage(NativeMethods.TVM_SELECTITEM, NativeMethods.TVGN_DROPHILITE, null);
 
            // Windows TreeView pushes its own message loop in WM_xBUTTONDOWN, so fire the 
            // event before calling defWndProc or else it won't get fired until the button
            // comes back up. 
            OnMouseDown(new MouseEventArgs(button, clicks, NativeMethods.Util.SignedLOWORD(m.LParam), NativeMethods.Util.SignedHIWORD(m.LParam), 0));

            //If Validation is cancelled dont fire any events through the Windows TreeView's message loop...
            if (!ValidationCancelled) { 
                DefWndProc(ref m);
            } 
 
        }
 


        /// 
        ///  
        ///     Performs custom draw handling
        ///  
        ///  
        private void CustomDraw(ref Message m) {
            NativeMethods.NMTVCUSTOMDRAW nmcd = (NativeMethods.NMTVCUSTOMDRAW)m.GetLParam(typeof(NativeMethods.NMTVCUSTOMDRAW)); 

            // Find out which stage we're drawing
            switch (nmcd.nmcd.dwDrawStage) {
                // Do we want OwnerDraw for this paint cycle? 
                case NativeMethods.CDDS_PREPAINT:
                    m.Result = (IntPtr)NativeMethods.CDRF_NOTIFYITEMDRAW; // yes, we do... 
                    return; 
                    // We've got opt-in on owner draw for items - so handle each one.
                case NativeMethods.CDDS_ITEMPREPAINT: 
                    // get the node
                    Debug.Assert(nmcd.nmcd.dwItemSpec != IntPtr.Zero, "Invalid node handle in ITEMPREPAINT");
                    TreeNode node = NodeFromHandle((IntPtr)nmcd.nmcd.dwItemSpec);
 
                    if (node == null) {
                       // this can happen if we are presently inserting the node - it hasn't yet 
                       // been added to the handle table 

                       m.Result = (IntPtr)(NativeMethods.CDRF_SKIPDEFAULT); 
                       return;
                    }

 
                    int state = nmcd.nmcd.uItemState;
 
 
                    // The commctrl TreeView allows you to draw the whole row of a node
                    // or nothing at all. The way we provide OwnerDrawText is by asking it 
                    // to draw everything but the text - to do this, we set text color same
                    // as background color.
                    if (drawMode == TreeViewDrawMode.OwnerDrawText)
                    { 
                        nmcd.clrText = nmcd.clrTextBk;
                        Marshal.StructureToPtr(nmcd, m.LParam, false); 
                        m.Result = (IntPtr) (NativeMethods.CDRF_NEWFONT | NativeMethods.CDRF_NOTIFYPOSTPAINT); 
                        return;
                    } 
                    else if (drawMode == TreeViewDrawMode.OwnerDrawAll)
                    {
                        Graphics g = Graphics.FromHdcInternal(nmcd.nmcd.hdc);
 
                        DrawTreeNodeEventArgs e;
 
                        try { 
                            Rectangle bounds = node.RowBounds;
 
                            NativeMethods.SCROLLINFO si = new NativeMethods.SCROLLINFO();
                            si.cbSize = Marshal.SizeOf(typeof(NativeMethods.SCROLLINFO));
                            si.fMask = NativeMethods.SIF_POS;
                            if (UnsafeNativeMethods.GetScrollInfo(new HandleRef(this, Handle), NativeMethods.SB_HORZ,si) != false) { 
                                // VsW : 432718
                                // need to get the correct bounds if horizontal scroll bar is shown. 
                                // In this case the bounds.X needs to be negative and width needs to be updated to the increased width (scrolled region). 
                                int value = si.nPos;
                                if (value > 0) 
                                {
                                    bounds.X -= value;
                                    bounds.Width += value;
                                } 
                            }
                            e = new DrawTreeNodeEventArgs(g, node, bounds, (TreeNodeStates) (state)); 
                            OnDrawNode(e); 
                        }
                        finally { 
                            g.Dispose();
                        }

                        if (!e.DrawDefault) { 
                            m.Result = (IntPtr)(NativeMethods.CDRF_SKIPDEFAULT);
                            return; 
                        } 
                    }
 
                    //TreeViewDrawMode.Normal case
#if DEBUGGING
                    // Diagnostic output
                    Debug.WriteLine("Itemstate: "+state); 
                    Debug.WriteLine("Itemstate: "+
                                            "\nDISABLED" + (((state & NativeMethods.CDIS_DISABLED) != 0) ? "TRUE" : "FALSE") + 
                                            "\nHOT" + (((state & NativeMethods.CDIS_HOT) != 0) ? "TRUE" : "FALSE") + 
                                            "\nGRAYED" + (((state & NativeMethods.CDIS_GRAYED) != 0) ? "TRUE" : "FALSE") +
                                            "\nSELECTED" + (((state & NativeMethods.CDIS_SELECTED) != 0) ? "TRUE" : "FALSE") + 
                                            "\nFOCUS" + (((state & NativeMethods.CDIS_FOCUS) != 0) ? "TRUE" : "FALSE") +
                                            "\nDEFAULT" + (((state & NativeMethods.CDIS_DEFAULT) != 0) ? "TRUE" : "FALSE") +
                                            "\nMARKED" + (((state & NativeMethods.CDIS_MARKED) != 0) ? "TRUE" : "FALSE") +
                                            "\nINDETERMINATE" + (((state & NativeMethods.CDIS_INDETERMINATE) != 0) ? "TRUE" : "FALSE")); 
#endif
 
                   OwnerDrawPropertyBag renderinfo = GetItemRenderStyles(node,state); 

                    // TreeView has problems with drawing items at times; it gets confused 
                    // as to which colors apply to which items (see focus rectangle shifting;
                    // when one item is selected, click and hold on another). This needs to be fixed.

                    bool colordelta = false; 
                    Color riFore = renderinfo.ForeColor;
                    Color riBack = renderinfo.BackColor; 
                    if (renderinfo != null && !riFore.IsEmpty) { 
                        nmcd.clrText = ColorTranslator.ToWin32(riFore);
                        colordelta = true; 
                    }
                    if (renderinfo != null && !riBack.IsEmpty) {
                        nmcd.clrTextBk = ColorTranslator.ToWin32(riBack);
                        colordelta = true; 
                    }
                    if (colordelta) { 
                        Marshal.StructureToPtr(nmcd, m.LParam, false); 
                    }
                    if (renderinfo != null && renderinfo.Font != null) { 
                        // Mess with the DC directly...
                        SafeNativeMethods.SelectObject(new HandleRef(nmcd.nmcd, nmcd.nmcd.hdc), new HandleRef(renderinfo, renderinfo.FontHandle));
                        // There is a problem in winctl that clips node fonts if the fontsize
                        // is larger than the treeview font size. The behavior is much better in comctl 5 and above. 
                        m.Result = (IntPtr)NativeMethods.CDRF_NEWFONT;
                        return; 
                    } 

                    // fall through and do the default drawing work 
                    goto default;

                case (NativeMethods.CDDS_ITEMPOSTPAINT):
                    //User draws only the text in OwnerDrawText mode, as explained in comments above 
                    if (drawMode == TreeViewDrawMode.OwnerDrawText)
                    { 
                        Debug.Assert(nmcd.nmcd.dwItemSpec != IntPtr.Zero, "Invalid node handle in ITEMPOSTPAINT"); 

                        // Get the node 
                        node = NodeFromHandle((IntPtr)nmcd.nmcd.dwItemSpec);

                        if (node == null) {
                            // this can happen if we are presently inserting the node - it hasn't yet 
                            // been added to the handle table
                            return; 
                        } 

 

                        Graphics g = Graphics.FromHdcInternal(nmcd.nmcd.hdc);

                        DrawTreeNodeEventArgs e; 

                        try { 
                            Rectangle bounds = node.Bounds; 
                            Size textSize = TextRenderer.MeasureText(node.Text, node.TreeView.Font);
                            Point textLoc = new Point(bounds.X -1, bounds.Y); // required to center the text 
                            bounds = new Rectangle(textLoc, new Size(textSize.Width, bounds.Height));

                            e = new DrawTreeNodeEventArgs(g, node, bounds, (TreeNodeStates) (nmcd.nmcd.uItemState));
                            OnDrawNode(e); 

                            if (e.DrawDefault) { 
                                //Simulate default text drawing here 
                                TreeNodeStates curState = e.State;
 
                                Font font = (node.NodeFont != null) ? node.NodeFont : node.TreeView.Font;
                                Color color = (((curState & TreeNodeStates.Selected) == TreeNodeStates.Selected) && node.TreeView.Focused) ? SystemColors.HighlightText : (node.ForeColor != Color.Empty) ? node.ForeColor : node.TreeView.ForeColor;

                                // Draw the actual node. 
                                if ((curState & TreeNodeStates.Selected) == TreeNodeStates.Selected)
                                { 
                                	g.FillRectangle(SystemBrushes.Highlight, bounds); 
                                	ControlPaint.DrawFocusRectangle(g, bounds, color, SystemColors.Highlight);
                                	TextRenderer.DrawText(g, e.Node.Text, font, bounds, color, TextFormatFlags.Default); 
                                }
                                else
                                {
                                    // For Dev10 bug 478621: We need to draw the BackColor of 
                                    // nodes same as BackColor of treeview.
                                    using (Brush brush = new SolidBrush(BackColor)) 
                                    { 
                                        g.FillRectangle(brush, bounds);
                                    } 

                                    TextRenderer.DrawText(g, e.Node.Text, font, bounds, color, TextFormatFlags.Default);
                                }
                            } 
                        }
                        finally { 
                            g.Dispose(); 
                        }
 
                        m.Result = (IntPtr)NativeMethods.CDRF_NOTIFYSUBITEMDRAW;
                        return;
                    }
 
                    goto default;
 
                default: 
                    // just in case we get a spurious message, tell it to do the right thing
                    m.Result = (IntPtr)NativeMethods.CDRF_DODEFAULT; 
                    return;
                }
        }
 
        /// 
        ///  
        ///     Generates colors for each item. This can be overridden to provide colors on a per state/per node 
        ///     basis, rather than using the ForeColor/BackColor/NodeFont properties on TreeNode.
        /// 
        /// 
        /// 
        protected OwnerDrawPropertyBag GetItemRenderStyles(TreeNode node, int state) {
            OwnerDrawPropertyBag retval = new OwnerDrawPropertyBag(); 
            if (node == null || node.propBag == null) return retval;
 
            // we only change colors if we're displaying things normally 
            if ((state & (NativeMethods.CDIS_SELECTED | NativeMethods.CDIS_GRAYED | NativeMethods.CDIS_HOT | NativeMethods.CDIS_DISABLED))==0) {
                retval.ForeColor = node.propBag.ForeColor; 
                retval.BackColor = node.propBag.BackColor;
            }
            retval.Font = node.propBag.Font;
            return retval; 
        }
 
        private unsafe bool WmShowToolTip(ref Message m) 
        {
            NativeMethods.NMHDR* nmhdr = (NativeMethods.NMHDR*)m.LParam; 
            IntPtr tooltipHandle = nmhdr->hwndFrom;


            NativeMethods.TV_HITTESTINFO tvhip = new NativeMethods.TV_HITTESTINFO(); 
            Point pos = Cursor.Position;
            pos = PointToClientInternal(pos); 
            tvhip.pt_x = pos.X; 
            tvhip.pt_y = pos.Y;
            IntPtr hnode = UnsafeNativeMethods.SendMessage(new HandleRef(this, Handle), NativeMethods.TVM_HITTEST, 0, tvhip); 

            if (hnode != IntPtr.Zero && ((tvhip.flags & NativeMethods.TVHT_ONITEM) != 0)) {

                TreeNode tn = NodeFromHandle(hnode); 
                if (tn != null)
                { 
                    if (!ShowNodeToolTips) // default ToolTips 
                    {
                        Rectangle bounds = tn.Bounds; 
                        bounds.Location = this.PointToScreen(bounds.Location);

                        UnsafeNativeMethods.SendMessage(new HandleRef(this, tooltipHandle), NativeMethods.TTM_ADJUSTRECT, 1, ref bounds);
                        SafeNativeMethods.SetWindowPos(new HandleRef(this, tooltipHandle), 
                                NativeMethods.HWND_TOPMOST, bounds.Left, bounds.Top, 0, 0, NativeMethods.SWP_NOACTIVATE | NativeMethods.SWP_NOSIZE | NativeMethods.SWP_NOZORDER);
                        return true; 
                    } 
                }
            } 
            return false;
        }

        ///  
        /// 
        ///  
        ///  
        private void WmNeedText(ref Message m) {
            NativeMethods.TOOLTIPTEXT ttt = (NativeMethods.TOOLTIPTEXT) m.GetLParam(typeof(NativeMethods.TOOLTIPTEXT)); 
            string tipText = controlToolTipText;

            NativeMethods.TV_HITTESTINFO tvhip = new NativeMethods.TV_HITTESTINFO();
            Point pos = Cursor.Position; 
            pos = PointToClientInternal(pos);
            tvhip.pt_x = pos.X; 
            tvhip.pt_y = pos.Y; 
            IntPtr hnode = UnsafeNativeMethods.SendMessage(new HandleRef(this, Handle), NativeMethods.TVM_HITTEST, 0, tvhip);
            if (hnode != IntPtr.Zero && ((tvhip.flags & NativeMethods.TVHT_ONITEM) != 0)) { 
                TreeNode tn = NodeFromHandle(hnode);
                if (ShowNodeToolTips && tn != null && (!string.IsNullOrEmpty(tn.ToolTipText))) {
                    tipText = tn.ToolTipText;
                } 
                else if (tn != null && tn.Bounds.Right > this.Bounds.Right) {
                    tipText = tn.Text; 
                } 
                else {
                    tipText = null; 
                }
            }
            ttt.lpszText = tipText;
            ttt.hinst = IntPtr.Zero; 

            // RightToLeft reading order 
            // 
            if (RightToLeft == RightToLeft.Yes) {
                ttt.uFlags |= NativeMethods.TTF_RTLREADING; 
            }
            Marshal.StructureToPtr(ttt, m.LParam, false);
        }
 

        private unsafe void WmNotify(ref Message m) { 
            NativeMethods.NMHDR* nmhdr = (NativeMethods.NMHDR *)m.LParam; 

            // Custom draw code is handled separately. 
            //
            if ((nmhdr->code ==  NativeMethods.NM_CUSTOMDRAW)) {
                CustomDraw(ref m);
            } 
            else {
 
                NativeMethods.NMTREEVIEW* nmtv = (NativeMethods.NMTREEVIEW*)m.LParam; 

                switch (nmtv->nmhdr.code) { 
                    case NativeMethods.TVN_ITEMEXPANDINGA:
                    case NativeMethods.TVN_ITEMEXPANDINGW:
                        m.Result = TvnExpanding(nmtv);
                        break; 
                    case NativeMethods.TVN_ITEMEXPANDEDA:
                    case NativeMethods.TVN_ITEMEXPANDEDW: 
                        TvnExpanded(nmtv); 
                        break;
                    case NativeMethods.TVN_SELCHANGINGA: 
                    case NativeMethods.TVN_SELCHANGINGW:
                        m.Result = TvnSelecting(nmtv);
                        break;
                    case NativeMethods.TVN_SELCHANGEDA: 
                    case NativeMethods.TVN_SELCHANGEDW:
                        TvnSelected(nmtv); 
                        break; 
                    case NativeMethods.TVN_BEGINDRAGA:
                    case NativeMethods.TVN_BEGINDRAGW: 
                        TvnBeginDrag(MouseButtons.Left, nmtv);
                        break;
                    case NativeMethods.TVN_BEGINRDRAGA:
                    case NativeMethods.TVN_BEGINRDRAGW: 
                        TvnBeginDrag(MouseButtons.Right, nmtv);
                        break; 
                    case NativeMethods.TVN_BEGINLABELEDITA: 
                    case NativeMethods.TVN_BEGINLABELEDITW:
                        m.Result = TvnBeginLabelEdit((NativeMethods.NMTVDISPINFO)m.GetLParam(typeof(NativeMethods.NMTVDISPINFO))); 
                        break;
                    case NativeMethods.TVN_ENDLABELEDITA:
                    case NativeMethods.TVN_ENDLABELEDITW:
                        m.Result = TvnEndLabelEdit((NativeMethods.NMTVDISPINFO)m.GetLParam(typeof(NativeMethods.NMTVDISPINFO))); 
                        break;
                    case NativeMethods.NM_CLICK: 
                    case NativeMethods.NM_RCLICK: 
                        MouseButtons button = MouseButtons.Left;
 
                        NativeMethods.TV_HITTESTINFO tvhip = new NativeMethods.TV_HITTESTINFO();
                        Point pos = Cursor.Position;
                        pos = PointToClientInternal(pos);
                        tvhip.pt_x = pos.X; 
                        tvhip.pt_y = pos.Y;
                        IntPtr hnode = UnsafeNativeMethods.SendMessage(new HandleRef(this, Handle), NativeMethods.TVM_HITTEST, 0, tvhip); 
                        if (nmtv->nmhdr.code != NativeMethods.NM_CLICK 
                                    || (tvhip.flags & NativeMethods.TVHT_ONITEM) != 0) {
                                button = nmtv->nmhdr.code == NativeMethods.NM_CLICK 
                                    ? MouseButtons.Left : MouseButtons.Right;
                        }

                        // The treeview's WndProc doesn't get the WM_LBUTTONUP messages when 
                        // LBUTTONUP happens on TVHT_ONITEM. This is a comctl quirk.
                        // We work around that by calling OnMouseUp here. 
                        if (nmtv->nmhdr.code != NativeMethods.NM_CLICK 
                            || (tvhip.flags & NativeMethods.TVHT_ONITEM) != 0 || FullRowSelect) {
                            if (hnode != IntPtr.Zero && !ValidationCancelled) { 
                                OnNodeMouseClick(new TreeNodeMouseClickEventArgs(NodeFromHandle(hnode), button, 1, pos.X, pos.Y));
                                OnClick(new MouseEventArgs(button, 1, pos.X, pos.Y, 0));
                                OnMouseClick(new MouseEventArgs(button, 1, pos.X, pos.Y, 0));
 
                            }
                        } 
                        if (nmtv->nmhdr.code == NativeMethods.NM_RCLICK) { 
                            TreeNode treeNode = NodeFromHandle(hnode);
                            if (treeNode != null && (treeNode.ContextMenu != null || treeNode.ContextMenuStrip != null)) { 
                                ShowContextMenu(treeNode);
                            }
                            else {
                                treeViewState[TREEVIEWSTATE_showTreeViewContextMenu] = true; 
                                SendMessage(NativeMethods.WM_CONTEXTMENU, Handle, SafeNativeMethods.GetMessagePos());
                            } 
                            m.Result = (IntPtr)1; 

                        } 

                        if (!treeViewState[TREEVIEWSTATE_mouseUpFired]) {
                            if (nmtv->nmhdr.code != NativeMethods.NM_CLICK
                            || (tvhip.flags & NativeMethods.TVHT_ONITEM) != 0) { 
                                // The treeview's WndProc doesn't get the WM_LBUTTONUP messages when
                                // LBUTTONUP happens on TVHT_ONITEM. This is a comctl quirk. 
                                // We work around that by calling OnMouseUp here. 
                                OnMouseUp(new MouseEventArgs(button, 1, pos.X, pos.Y, 0));
                                treeViewState[TREEVIEWSTATE_mouseUpFired] = true; 
                            }

                        }
                        break; 
                }
            } 
        } 

        ///  
        /// 
        ///     Shows the context menu for the Treenode.
        /// 
        ///  
        private void ShowContextMenu(TreeNode treeNode) {
 
            if (treeNode.ContextMenu != null || treeNode.ContextMenuStrip != null) { 

 
                ContextMenu contextMenu = treeNode.ContextMenu;
                ContextMenuStrip menu = treeNode.ContextMenuStrip;

                if (contextMenu != null) 
                {
 
                    NativeMethods.POINT pt = new NativeMethods.POINT(); 
                    UnsafeNativeMethods.GetCursorPos(pt);
 
                    // VS7 #38994
                    // The solution to this problem was found in MSDN Article ID: Q135788.
                    // Summary: the current window must be made the foreground window
                    // before calling TrackPopupMenuEx, and a task switch must be 
                    // forced after the call.
 
                    UnsafeNativeMethods.SetForegroundWindow(new HandleRef(this, this.Handle)); 

                    contextMenu.OnPopup( EventArgs.Empty ); 

                    SafeNativeMethods.TrackPopupMenuEx(new HandleRef(contextMenu, contextMenu.Handle),
                                             NativeMethods.TPM_VERTICAL,
                                             pt.x, 
                                             pt.y,
                                             new HandleRef(this, this.Handle), 
                                             null); 

                    // Force task switch (see above) 
                    UnsafeNativeMethods.PostMessage(new HandleRef(this, this.Handle), NativeMethods.WM_NULL, IntPtr.Zero, IntPtr.Zero);
                }
                // VsWhidbey : 432712.
                // Need to send TVM_SELECTITEM to highlight the node while the contextMenuStrip is being shown. 
                else if (menu != null)
                { 
                    UnsafeNativeMethods.PostMessage(new HandleRef(this, Handle), NativeMethods.TVM_SELECTITEM, NativeMethods.TVGN_DROPHILITE, treeNode.Handle); 
                    menu.ShowInternal(this, PointToClient(MousePosition),/*keyboardActivated*/false);
                    menu.Closing += new ToolStripDropDownClosingEventHandler(this.ContextMenuStripClosing); 
                }
            }
        }
 
        // VsWhidbey : 432712.
        // Need to send TVM_SELECTITEM to reset the node-highlighting while the contextMenuStrip is being closed so that the treeview reselects the SelectedNode. 
        private void ContextMenuStripClosing(object sender, ToolStripDropDownClosingEventArgs e) 
        {
            ContextMenuStrip strip = sender as ContextMenuStrip; 
            // Unhook the Event.
            strip.Closing -= new ToolStripDropDownClosingEventHandler(this.ContextMenuStripClosing);
            SendMessage(NativeMethods.TVM_SELECTITEM, NativeMethods.TVGN_DROPHILITE, null);
        } 

        private void WmPrint(ref Message m) { 
            base.WndProc(ref m); 

            if ((NativeMethods.PRF_NONCLIENT & (int)m.LParam) != 0 && Application.RenderWithVisualStyles && this.BorderStyle == BorderStyle.Fixed3D) { 
                IntSecurity.UnmanagedCode.Assert();
                try {
                    using (Graphics g = Graphics.FromHdc(m.WParam)) {
                        Rectangle rect = new Rectangle(0, 0, this.Size.Width - 1, this.Size.Height - 1); 
                        g.DrawRectangle(new Pen(VisualStyleInformation.TextControlBorder), rect);
                        rect.Inflate(-1, -1); 
                        g.DrawRectangle(SystemPens.Window, rect); 
                    }
                } 
                finally {
                    CodeAccessPermission.RevertAssert();
                }
            } 
        }
 
        ///  
        /// 
        ///  
        /// 
        [SecurityPermission(SecurityAction.LinkDemand, Flags=SecurityPermissionFlag.UnmanagedCode)]
        protected override void WndProc(ref Message m) {
            switch (m.Msg) { 
                case NativeMethods.WM_WINDOWPOSCHANGING:
                case NativeMethods.WM_NCCALCSIZE: 
                case NativeMethods.WM_WINDOWPOSCHANGED: 
                case NativeMethods.WM_SIZE:
                    // While we are changing size of treeView to avoid the scrollbar; dont respond to the window-sizing messages. 
                    if (treeViewState[TREEVIEWSTATE_stopResizeWindowMsgs])
                    {
                        //Debug.WriteLineIf(treeViewState[TREEVIEWSTATE_stopResizeWindowMsgs], "Sending message directly to DefWndProc() : " + m.ToString());
                        DefWndProc(ref m); 
                    }
                    else 
                    { 
                        base.WndProc(ref m);
                    } 
                    break;
               case NativeMethods.WM_HSCROLL:
                    base.WndProc(ref m);
                    if (DrawMode == TreeViewDrawMode.OwnerDrawAll) 
                    {
                        //VsW : 432718 
                        Invalidate(); 
                    }
                    break; 

        case NativeMethods.WM_PRINT:
            WmPrint(ref m);
            break; 
                case NativeMethods.TVM_SETITEMA:
                case NativeMethods.TVM_SETITEMW: 
                    base.WndProc(ref m); 
                    if (this.CheckBoxes) {
                        NativeMethods.TV_ITEM item = (NativeMethods.TV_ITEM) m.GetLParam(typeof(NativeMethods.TV_ITEM)); 
                        // Check for invalid node handle
                        if (item.hItem != IntPtr.Zero) {
                            NativeMethods.TV_ITEM item1 = new NativeMethods.TV_ITEM();
                            item1.mask = NativeMethods.TVIF_HANDLE | NativeMethods.TVIF_STATE; 
                            item1.hItem = item.hItem;
                            item1.stateMask = NativeMethods.TVIS_STATEIMAGEMASK; 
                            UnsafeNativeMethods.SendMessage(new HandleRef(null, this.Handle), NativeMethods.TVM_GETITEM, 0, ref item1); 

                            TreeNode node = NodeFromHandle(item.hItem); 
                            node.CheckedStateInternal = ((item1.state >> 12) > 1);
                        }
                    }
                    break; 
                case NativeMethods.WM_NOTIFY:
                    NativeMethods.NMHDR nmhdr = (NativeMethods.NMHDR) m.GetLParam(typeof(NativeMethods.NMHDR)); 
                    switch (nmhdr.code) { 
                        case NativeMethods.TTN_GETDISPINFOA:
                        case NativeMethods.TTN_GETDISPINFOW: 
                            // MSDN:
                            // Setting the max width has the added benefit of enabling multiline
                            // tool tips!
                            // 
                            UnsafeNativeMethods.SendMessage(new HandleRef(nmhdr, nmhdr.hwndFrom), NativeMethods.TTM_SETMAXTIPWIDTH, 0, SystemInformation.MaxWindowTrackSize.Width);
                            WmNeedText(ref m); 
                            m.Result = (IntPtr)1; 
                            return;
 						case NativeMethods.TTN_SHOW: 
                            if (WmShowToolTip(ref m))
                            {
                                m.Result = (IntPtr)1;
                                return; 
                            }
                            else 
                            { 
                                base.WndProc(ref m);
                                break; 
                            }

                        default:
                             base.WndProc(ref m); 
                             break;
                    } 
                    break; 
                case NativeMethods.WM_REFLECT + NativeMethods.WM_NOTIFY:
                        WmNotify(ref m); 
                        break;
                case NativeMethods.WM_LBUTTONDBLCLK:
                    WmMouseDown(ref m, MouseButtons.Left, 2);
                    //just maintain state and fire double click.. in final mouseUp... 
                    treeViewState[TREEVIEWSTATE_doubleclickFired] = true;
                    //fire Up in the Wndproc !! 
                    treeViewState[TREEVIEWSTATE_mouseUpFired] = false; 
                    //problem getting the UP... outside the control...
                    // 
                    CaptureInternal = true;
                    break;
                case NativeMethods.WM_LBUTTONDOWN:
                    try 
                    {
                        treeViewState[TREEVIEWSTATE_ignoreSelects] = true; 
                        FocusInternal(); 
                    }
                    finally 
                    {
                       treeViewState[ TREEVIEWSTATE_ignoreSelects] = false;
                    }
                    //Always Reset the MouseupFired.... 
                    treeViewState[TREEVIEWSTATE_mouseUpFired] = false;
                    NativeMethods.TV_HITTESTINFO tvhip = new NativeMethods.TV_HITTESTINFO(); 
                    tvhip.pt_x = NativeMethods.Util.SignedLOWORD(m.LParam); 
                    tvhip.pt_y = NativeMethods.Util.SignedHIWORD(m.LParam);
                    hNodeMouseDown = UnsafeNativeMethods.SendMessage(new HandleRef(this, Handle), NativeMethods.TVM_HITTEST, 0, tvhip); 

                    // This gets around the TreeView behavior of temporarily moving the selection
                    // highlight to a node when the user clicks on its checkbox.
                    if ((tvhip.flags & NativeMethods.TVHT_ONITEMSTATEICON) != 0) { 
                        //We donot pass the Message to the Control .. so fire MouseDowm ...
                        OnMouseDown(new MouseEventArgs(MouseButtons.Left, 1, NativeMethods.Util.SignedLOWORD(m.LParam), NativeMethods.Util.SignedHIWORD(m.LParam), 0)); 
                        if (!ValidationCancelled && CheckBoxes) 
                        {
                            TreeNode node = NodeFromHandle(hNodeMouseDown); 
                            bool eventReturn = TreeViewBeforeCheck(node, TreeViewAction.ByMouse);
                            if (!eventReturn && node != null) {
                                node.CheckedInternal = !node.CheckedInternal;
                                TreeViewAfterCheck(node, TreeViewAction.ByMouse); 
                            }
                        } 
                        m.Result = IntPtr.Zero; 
                    }
                    else { 
                        WmMouseDown(ref m, MouseButtons.Left, 1);
                    }
                    downButton = MouseButtons.Left;
                    break; 
                case NativeMethods.WM_LBUTTONUP:
                case NativeMethods.WM_RBUTTONUP: 
                    NativeMethods.TV_HITTESTINFO tvhi = new NativeMethods.TV_HITTESTINFO(); 
                    tvhi.pt_x = NativeMethods.Util.SignedLOWORD(m.LParam);
                    tvhi.pt_y = NativeMethods.Util.SignedHIWORD(m.LParam); 
                    IntPtr hnode = UnsafeNativeMethods.SendMessage(new HandleRef(this, Handle), NativeMethods.TVM_HITTEST, 0, tvhi);
                    //Important for CheckBoxes ... click needs to be fired ...
                    //
                    if(hnode != IntPtr.Zero) { 
                        if (!ValidationCancelled && !treeViewState[TREEVIEWSTATE_doubleclickFired] & !treeViewState[TREEVIEWSTATE_mouseUpFired]) {
                            //OnClick(EventArgs.Empty); 
 
                            //If the hit-tested node here is the same as the node we hit-tested
                            //on mouse down then we will fire our OnNodeMoseClick event. 
                            if (hnode == hNodeMouseDown) {
                                OnNodeMouseClick(new TreeNodeMouseClickEventArgs(NodeFromHandle(hnode), downButton, 1, NativeMethods.Util.SignedLOWORD(m.LParam), NativeMethods.Util.SignedHIWORD(m.LParam)));
                            }
 
                            OnClick(new MouseEventArgs(downButton, 1, NativeMethods.Util.SignedLOWORD(m.LParam), NativeMethods.Util.SignedHIWORD(m.LParam), 0));
                            OnMouseClick(new MouseEventArgs(downButton, 1, NativeMethods.Util.SignedLOWORD(m.LParam), NativeMethods.Util.SignedHIWORD(m.LParam), 0)); 
                        } 

                        if (treeViewState[TREEVIEWSTATE_doubleclickFired]) { 
                            treeViewState[TREEVIEWSTATE_doubleclickFired] = false;
                            if (!ValidationCancelled) {
                                 //OnDoubleClick(EventArgs.Empty);
                                 OnNodeMouseDoubleClick(new TreeNodeMouseClickEventArgs(NodeFromHandle(hnode), downButton, 2, NativeMethods.Util.SignedLOWORD(m.LParam), NativeMethods.Util.SignedHIWORD(m.LParam))); 
                                 OnDoubleClick(new MouseEventArgs(downButton, 2, NativeMethods.Util.SignedLOWORD(m.LParam), NativeMethods.Util.SignedHIWORD(m.LParam), 0));
                                 OnMouseDoubleClick(new MouseEventArgs(downButton, 2, NativeMethods.Util.SignedLOWORD(m.LParam), NativeMethods.Util.SignedHIWORD(m.LParam), 0)); 
                            } 
                        }
                    } 
                    if (!treeViewState[TREEVIEWSTATE_mouseUpFired])
                        OnMouseUp(new MouseEventArgs(downButton, 1, NativeMethods.Util.SignedLOWORD(m.LParam), NativeMethods.Util.SignedHIWORD(m.LParam), 0));
                    treeViewState[TREEVIEWSTATE_doubleclickFired] = false;
                    treeViewState[TREEVIEWSTATE_mouseUpFired] = false; 
                    CaptureInternal = false;
 
                    //always clear our hit-tested node we cached on mouse down 
                    hNodeMouseDown = IntPtr.Zero;
                    break; 
                case NativeMethods.WM_MBUTTONDBLCLK:
                    //fire Up in the Wndproc !!
                    treeViewState[TREEVIEWSTATE_mouseUpFired] = false;
                    WmMouseDown(ref m, MouseButtons.Middle, 2); 
                    break;
                case NativeMethods.WM_MBUTTONDOWN: 
                    //Always Reset the MouseupFired.... 
                    treeViewState[TREEVIEWSTATE_mouseUpFired] = false;
                    WmMouseDown(ref m, MouseButtons.Middle, 1); 
                    downButton = MouseButtons.Middle;
                    break;
                case NativeMethods.WM_MOUSELEAVE:
                    // if the mouse leaves and then reenters the TreeView 
                    // NodeHovered events should be raised.
                    prevHoveredNode = null; 
                    base.WndProc(ref m); 
                    break;
                case NativeMethods.WM_RBUTTONDBLCLK: 
                    WmMouseDown(ref m, MouseButtons.Right, 2);
                    //just maintain state and fire double click.. in final mouseUp...
                    treeViewState[TREEVIEWSTATE_doubleclickFired] = true;
                    //fire Up in the Wndproc !! 
                    treeViewState[TREEVIEWSTATE_mouseUpFired] = false;
                    //problem getting the UP... outside the control... 
                    // 
                    CaptureInternal = true;
                    break; 
                case NativeMethods.WM_RBUTTONDOWN:
                    //Always Reset the MouseupFired....
                    treeViewState[TREEVIEWSTATE_mouseUpFired] = false;
                    //Cache the hit-tested node for verification when mouse up is fired 
                    NativeMethods.TV_HITTESTINFO tvhit = new NativeMethods.TV_HITTESTINFO();
                    tvhit.pt_x = NativeMethods.Util.SignedLOWORD(m.LParam); 
                    tvhit.pt_y = NativeMethods.Util.SignedHIWORD(m.LParam); 
                    hNodeMouseDown = UnsafeNativeMethods.SendMessage(new HandleRef(this, Handle), NativeMethods.TVM_HITTEST, 0, tvhit);
 
                    WmMouseDown(ref m, MouseButtons.Right, 1);
                    downButton = MouseButtons.Right;
                    break;
                    //# VS7 15052 
                case NativeMethods.WM_SYSCOLORCHANGE:
                    SendMessage(NativeMethods.TVM_SETINDENT, Indent, 0); 
                    base.WndProc(ref m); 
                    break;
                case NativeMethods.WM_SETFOCUS: 
                     // If we get focus through the LBUttonDown .. we might have done the validation...
                     // so skip it..
                     if (treeViewState[TREEVIEWSTATE_lastControlValidated])
                     { 
                        treeViewState[TREEVIEWSTATE_lastControlValidated] = false;
                        WmImeSetFocus(); 
                        DefWndProc(ref m); 
                        OnGotFocus(EventArgs.Empty);
                     } 
                     else
                     {
                        base.WndProc(ref m);
                     } 
                     break;
                case NativeMethods.WM_CONTEXTMENU: 
                    if (treeViewState[TREEVIEWSTATE_showTreeViewContextMenu]) { 
                        treeViewState[TREEVIEWSTATE_showTreeViewContextMenu] = false;
                        base.WndProc(ref m); 
                    }
                    else {
                        // this is the Shift + F10 Case....
                        TreeNode treeNode = SelectedNode; 
                        if (treeNode != null && (treeNode.ContextMenu != null || treeNode.ContextMenuStrip !=null)) {
                            Point client; 
                            client = new Point(treeNode.Bounds.X , treeNode.Bounds.Y + treeNode.Bounds.Height / 2); 
                            // VisualStudio7 # 156, only show the context menu when clicked in the client area
                            if (ClientRectangle.Contains( client )) { 
                                if (treeNode.ContextMenu != null) {
                                    treeNode.ContextMenu.Show(this, client);
                                }
                                else if (treeNode.ContextMenuStrip !=null) { 
                                    bool keyboardActivated =  (unchecked((int)(long)m.LParam) == -1);
                                    treeNode.ContextMenuStrip.ShowInternal(this, client, keyboardActivated); 
                                } 
                            }
                        } 
                        else {
                            // in this case we dont have a selected node.  The base
                            // will ensure we're constrained to the client area.
                            base.WndProc (ref m); 
                        }
                    } 
                    break; 

 
                default:
                    base.WndProc(ref m);
                    break;
            } 
        }
    } 
} 

// File provided for Reference Use Only by Microsoft Corporation (c) 2007.


                        

Link Menu

Network programming in C#, Network Programming in VB.NET, Network Programming in .NET
This book is available now!
Buy at Amazon US or
Buy at Amazon UK