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.
<?xml:namespace prefix = o ns = "urn:schemas-microsoft-com:office:office" />
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>
private bool isExpandOrCollapseMouseClick;
#endregion
public BaseTreeView()
{
InitializeComponent();
}
private method#region private method
/**//// <summary>
/// Dispose the internal object of treeview.
/// </summary>
private void DisposeInternalObject()
{
if (internalGraphics != null)
{
internalGraphics.Dispose();
}
if (internalBitmap != null)
{
internalBitmap.Dispose();
}
}
#endregion
public method#region public method
protected override void OnAfterExpand(TreeViewEventArgs e)
{
isExpandOrCollapseMouseClick = true;
}
protected override void 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>
protected override void 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>
protected override void WndProc(ref Message message)
{
const int WM_PAINT = 0x000F;
const int WM_PRINTCLIENT = 0x0318;
const int 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)
]
public new event PaintEventHandler Paint
{
add { base.Paint += value; }
remove { base.Paint -= value; }
}
private void 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);
}
}
protected override void OnPaint(PaintEventArgs pe)
{
// TODO: Add custom paint code here
foreach (TreeNode node in this.Nodes)
{
OnPaintChildNode(node,pe);
}
base.OnPaint(pe);
}
protected override void 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
}
{
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>
private bool isExpandOrCollapseMouseClick;
#endregion
public BaseTreeView()
{
InitializeComponent();
}
private method#region private method
/**//// <summary>
/// Dispose the internal object of treeview.
/// </summary>
private void DisposeInternalObject()
{
if (internalGraphics != null)
{
internalGraphics.Dispose();
}
if (internalBitmap != null)
{
internalBitmap.Dispose();
}
}
#endregion
public method#region public method
protected override void OnAfterExpand(TreeViewEventArgs e)
{
isExpandOrCollapseMouseClick = true;
}
protected override void 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>
protected override void 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>
protected override void WndProc(ref Message message)
{
const int WM_PAINT = 0x000F;
const int WM_PRINTCLIENT = 0x0318;
const int 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)
]
public new event PaintEventHandler Paint
{
add { base.Paint += value; }
remove { base.Paint -= value; }
}
private void 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);
}
}
protected override void OnPaint(PaintEventArgs pe)
{
// TODO: Add custom paint code here
foreach (TreeNode node in this.Nodes)
{
OnPaintChildNode(node,pe);
}
base.OnPaint(pe);
}
protected override void 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
}
If any question please reply me.