We recently need a special tree view control that included some Checkbox or Radio controls in some tree node in a VSTO project. Some of complex nodes included checkbox controls or radio controls but others nodes maybe only is a simply tree node in same TreeView control. If we set value of the property named Checkboxes is “true”, all of the node are included a Checkbox in the TreeView controls, otherwise it will have not any checkbox controls. So I have to redesign a control to implements these features. I decided to inherit directly from the TreeView class instead of create a new class. I overwrite the method named (OnPaint, WndProc, OnResize etc) and add some new method that will draw a CheckBox control or Radio control in a tree node.
public partial class BaseTreeView : TreeView { private define#region private define private Bitmap internalBitmap =null; private Graphics internalGraphics =null; /**////<summary> /// Indicates whether the OnMouseClick event is raised by expand or collapse a tree node. ///</summary> privatebool isExpandOrCollapseMouseClick; #endregion public BaseTreeView() { InitializeComponent(); } private method#region private method /**////<summary> /// Dispose the internal object of treeview. ///</summary> privatevoid DisposeInternalObject() { if (internalGraphics !=null) { internalGraphics.Dispose(); } if (internalBitmap !=null) { internalBitmap.Dispose(); } } #endregion public method#region public method protectedoverridevoid OnAfterExpand(TreeViewEventArgs e) { isExpandOrCollapseMouseClick =true; } protectedoverridevoid OnAfterCollapse(TreeViewEventArgs e) { isExpandOrCollapseMouseClick =true; //throw new Exception("The method or operation is not implemented."); } /**////<summary> /// override the OnResize method ///</summary> ///<param name="e"></param> protectedoverridevoid OnResize(EventArgs e) { if (internalBitmap ==null|| internalBitmap.Width != Width || internalBitmap.Height != Height) { if (Width !=0&& Height !=0) { DisposeInternalObject(); internalBitmap =new Bitmap(Width, Height); internalGraphics = Graphics.FromImage(internalBitmap); } } } /**////<summary>Occurs when a Windows message is dispatched.</summary> ///<param name="message">Message to process.</param> ///<remarks>Overrides WM_PAINT, WM_ERASEBKGND.</remarks> protectedoverridevoid WndProc(ref Message message) { constint WM_PAINT =0x000F; constint WM_PRINTCLIENT =0x0318; constint WM_ERASEBKGND =0x0014; switch (message.Msg) { case WM_ERASEBKGND: //removes flicker return; case WM_PAINT: // The designer host does not call OnResize() if (internalGraphics ==null) { OnResize(EventArgs.Empty); } //Set up Win32.RECT updateRect =new Win32.RECT(); if (Win32.GetUpdateRect(message.HWnd, ref updateRect, false) ==0) { break; } Win32.PAINTSTRUCT paintStruct =new Win32.PAINTSTRUCT(); IntPtr screenHdc = Win32.BeginPaint(message.HWnd, ref paintStruct); using (Graphics screenGraphics = Graphics.FromHdc(screenHdc)) { //Draw Internal Graphics IntPtr hdc = internalGraphics.GetHdc(); Message printClientMessage = Message.Create(Handle, WM_PRINTCLIENT, hdc, IntPtr.Zero); DefWndProc(ref printClientMessage); internalGraphics.ReleaseHdc(hdc); //Add the missing OnPaint() call OnPaint(new PaintEventArgs(internalGraphics, Rectangle.FromLTRB( updateRect.left, updateRect.top, updateRect.right, updateRect.bottom))); //Draw Screen Graphics screenGraphics.DrawImage(internalBitmap, 0, 0); } //Tear down Win32.EndPaint(message.HWnd, ref paintStruct); return; } base.WndProc(ref message); } /**////<summary>Occurs when the control is redrawn.</summary> ///<remarks>Re enable browsing attributes for the Paint Event.</remarks> [ EditorBrowsableAttribute(EditorBrowsableState.Always), BrowsableAttribute(true) ] publicnewevent PaintEventHandler Paint { add { base.Paint += value; } remove { base.Paint -= value; } } privatevoid OnPaintChildNode(TreeNode parentNode, PaintEventArgs pe) { if (parentNode.Parent !=null) { OptionTreeNode optionNode = parentNode.Parent as OptionTreeNode; OptionItemTreeNode optionItem = parentNode as OptionItemTreeNode; if (optionNode !=null) { if (optionNode.IsOptionFolder ) { if ( optionItem !=null) { Rectangle rect =new Rectangle(0, 0, 16, 16); Bitmap bitmap =new Bitmap(16, 16); Graphics graphics = Graphics.FromImage(bitmap); if (optionNode.IsCheckBox) { if (parentNode.Checked) { ControlPaint.DrawCheckBox(graphics, rect, ButtonState.Checked | ButtonState.Flat); } else { ControlPaint.DrawCheckBox(graphics, rect, ButtonState.Normal | ButtonState.Flat); } } else { if (parentNode.Checked) { ControlPaint.DrawRadioButton(graphics, rect, ButtonState.Checked | ButtonState.Flat); } else { ControlPaint.DrawRadioButton(graphics, rect, ButtonState.Normal | ButtonState.Flat); } } rect = parentNode.Bounds; rect.Y = rect.Y +4; rect.Height =16; rect.Width =16; rect.X = rect.X -40; pe.Graphics.DrawImage(bitmap, rect); } } } } if (parentNode.Nodes ==null) { return; } foreach (TreeNode node in parentNode.Nodes) { OnPaintChildNode(node,pe); } } protectedoverridevoid OnPaint(PaintEventArgs pe) { // TODO: Add custom paint code here foreach (TreeNode node inthis.Nodes) { OnPaintChildNode(node,pe); } base.OnPaint(pe); } protectedoverridevoid OnMouseClick(MouseEventArgs e) { if (isExpandOrCollapseMouseClick ==true) { isExpandOrCollapseMouseClick =false; return; } TreeNode node = GetNodeAt(e.X, e.Y); if ((e.X > node.Bounds.Left) && (e.X < node.Bounds.Right) && (e.Y > node.Bounds.Top) && (e.Y < node.Bounds.Bottom)) return; if (node !=null) { if (node.Parent !=null) { OptionTreeNode optionNode = node.Parent as OptionTreeNode; if (optionNode !=null) { if (optionNode.IsOptionFolder) { if (optionNode.IsCheckBox) { node.Checked =!node.Checked; } else { TreeNode parentNode = node.Parent; { foreach(TreeNode objNode in parentNode.Nodes) { if (node.Equals(objNode)) { objNode.Checked =!objNode.Checked; } else { objNode.Checked =false; } } } } } } } } } #endregion }