// ***********************************************************************
// Assembly : HZH_Controls
// Created : 08-08-2019
//
// ***********************************************************************
//
// Copyright by Huang Zhenghui(黄正辉) All, QQ group:568015492 QQ:623128629 Email:623128629@qq.com
//
//
// Blog: https://www.cnblogs.com/bfyx
// GitHub:https://github.com/kwwwvagaa/NetWinformControl
// gitee:https://gitee.com/kwwwvagaa/net_winform_custom_control.git
//
// If you use this code, please keep this note.
// ***********************************************************************
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Diagnostics;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Windows.Forms;
using HZH_Controls.Properties;
namespace HZH_Controls.Controls
{
///
/// Class TreeViewEx.
/// Implements the
///
///
public partial class TreeViewEx : TreeView
{
///
/// The ws vscroll
///
private const int WS_VSCROLL = 2097152;
///
/// The GWL style
///
private const int GWL_STYLE = -16;
///
/// The LST tips
///
private Dictionary _lstTips = new Dictionary();
///
/// The tip font
///
private Font _tipFont = new Font("Arial Unicode MS", 12f);
///
/// The tip image
///
private Image _tipImage = Resources.tips;
///
/// The is show tip
///
private bool _isShowTip = false;
///
/// The is show by custom model
///
private bool _isShowByCustomModel = true;
///
/// The node height
///
private int _nodeHeight = 50;
///
/// The node down pic
///
private Image _nodeDownPic = Resources.list_add;
///
/// The node up pic
///
private Image _nodeUpPic = Resources.list_subtract;
///
/// The node background color
///
private Color _nodeBackgroundColor = Color.White;
///
/// The node fore color
///
private Color _nodeForeColor = Color.FromArgb(62, 62, 62);
///
/// The node is show split line
///
private bool _nodeIsShowSplitLine = false;
///
/// The node split line color
///
private Color _nodeSplitLineColor = Color.FromArgb(232, 232, 232);
///
/// The m node selected color
///
private Color m_nodeSelectedColor = Color.FromArgb(255, 77, 59);
///
/// The m node selected fore color
///
private Color m_nodeSelectedForeColor = Color.White;
///
/// The parent node can select
///
private bool _parentNodeCanSelect = true;
///
/// The tree font size
///
private SizeF treeFontSize = SizeF.Empty;
///
/// The BLN has v bar
///
private bool blnHasVBar = false;
///
/// Gets or sets the LST tips.
///
/// The LST tips.
public Dictionary LstTips
{
get
{
return this._lstTips;
}
set
{
this._lstTips = value;
}
}
///
/// Gets or sets the tip font.
///
/// The tip font.
[Category("自定义属性"), Description("角标文字字体")]
public Font TipFont
{
get
{
return this._tipFont;
}
set
{
this._tipFont = value;
}
}
///
/// Gets or sets the tip image.
///
/// The tip image.
[Category("自定义属性"), Description("是否显示角标")]
public Image TipImage
{
get
{
return this._tipImage;
}
set
{
this._tipImage = value;
}
}
///
/// Gets or sets a value indicating whether this instance is show tip.
///
/// true if this instance is show tip; otherwise, false.
[Category("自定义属性"), Description("是否显示角标")]
public bool IsShowTip
{
get
{
return this._isShowTip;
}
set
{
this._isShowTip = value;
}
}
///
/// Gets or sets a value indicating whether this instance is show by custom model.
///
/// true if this instance is show by custom model; otherwise, false.
[Category("自定义属性"), Description("使用自定义模式")]
public bool IsShowByCustomModel
{
get
{
return this._isShowByCustomModel;
}
set
{
this._isShowByCustomModel = value;
}
}
///
/// Gets or sets the height of the node.
///
/// The height of the node.
[Category("自定义属性"), Description("节点高度(IsShowByCustomModel=true时生效)")]
public int NodeHeight
{
get
{
return this._nodeHeight;
}
set
{
this._nodeHeight = value;
base.ItemHeight = value;
}
}
///
/// Gets or sets the node down pic.
///
/// The node down pic.
[Category("自定义属性"), Description("下翻图标(IsShowByCustomModel=true时生效)")]
public Image NodeDownPic
{
get
{
return this._nodeDownPic;
}
set
{
this._nodeDownPic = value;
}
}
///
/// Gets or sets the node up pic.
///
/// The node up pic.
[Category("自定义属性"), Description("上翻图标(IsShowByCustomModel=true时生效)")]
public Image NodeUpPic
{
get
{
return this._nodeUpPic;
}
set
{
this._nodeUpPic = value;
}
}
///
/// Gets or sets the color of the node background.
///
/// The color of the node background.
[Category("自定义属性"), Description("节点背景颜色(IsShowByCustomModel=true时生效)")]
public Color NodeBackgroundColor
{
get
{
return this._nodeBackgroundColor;
}
set
{
this._nodeBackgroundColor = value;
}
}
///
/// Gets or sets the color of the node fore.
///
/// The color of the node fore.
[Category("自定义属性"), Description("节点字体颜色(IsShowByCustomModel=true时生效)")]
public Color NodeForeColor
{
get
{
return this._nodeForeColor;
}
set
{
this._nodeForeColor = value;
}
}
///
/// Gets or sets a value indicating whether [node is show split line].
///
/// true if [node is show split line]; otherwise, false.
[Category("自定义属性"), Description("节点是否显示分割线(IsShowByCustomModel=true时生效)")]
public bool NodeIsShowSplitLine
{
get
{
return this._nodeIsShowSplitLine;
}
set
{
this._nodeIsShowSplitLine = value;
}
}
///
/// Gets or sets the color of the node split line.
///
/// The color of the node split line.
[Category("自定义属性"), Description("节点分割线颜色(IsShowByCustomModel=true时生效)")]
public Color NodeSplitLineColor
{
get
{
return this._nodeSplitLineColor;
}
set
{
this._nodeSplitLineColor = value;
}
}
///
/// Gets or sets the color of the node selected.
///
/// The color of the node selected.
[Category("自定义属性"), Description("选中节点背景颜色(IsShowByCustomModel=true时生效)")]
public Color NodeSelectedColor
{
get
{
return this.m_nodeSelectedColor;
}
set
{
this.m_nodeSelectedColor = value;
}
}
///
/// Gets or sets the color of the node selected fore.
///
/// The color of the node selected fore.
[Category("自定义属性"), Description("选中节点字体颜色(IsShowByCustomModel=true时生效)")]
public Color NodeSelectedForeColor
{
get
{
return this.m_nodeSelectedForeColor;
}
set
{
this.m_nodeSelectedForeColor = value;
}
}
///
/// Gets or sets a value indicating whether [parent node can select].
///
/// true if [parent node can select]; otherwise, false.
[Category("自定义属性"), Description("父节点是否可选中")]
public bool ParentNodeCanSelect
{
get
{
return this._parentNodeCanSelect;
}
set
{
this._parentNodeCanSelect = value;
}
}
///
/// Initializes a new instance of the class.
///
public TreeViewEx()
{
base.HideSelection = false;
base.DrawMode = TreeViewDrawMode.OwnerDrawAll;
base.DrawNode += new DrawTreeNodeEventHandler(this.treeview_DrawNode);
base.NodeMouseClick += new TreeNodeMouseClickEventHandler(this.TreeViewEx_NodeMouseClick);
base.SizeChanged += new EventHandler(this.TreeViewEx_SizeChanged);
base.AfterSelect += new TreeViewEventHandler(this.TreeViewEx_AfterSelect);
base.FullRowSelect = true;
base.ShowLines = false;
base.ShowPlusMinus = false;
base.ShowRootLines = false;
this.BackColor = Color.White;
this.BorderStyle = System.Windows.Forms.BorderStyle.None;
DoubleBuffered = true;
}
///
/// 重写 。
///
/// 要处理的 Windows。
protected override void WndProc(ref Message m)
{
if (m.Msg == 0x0014) // 禁掉清除背景消息WM_ERASEBKGND
return;
base.WndProc(ref m);
}
///
/// Handles the AfterSelect event of the TreeViewEx control.
///
/// The source of the event.
/// The instance containing the event data.
private void TreeViewEx_AfterSelect(object sender, TreeViewEventArgs e)
{
try
{
if (e.Node != null)
{
if (!this._parentNodeCanSelect)
{
if (e.Node.Nodes.Count > 0)
{
e.Node.Expand();
base.SelectedNode = e.Node.Nodes[0];
}
}
}
}
catch (Exception ex)
{
throw ex;
}
}
///
/// Handles the SizeChanged event of the TreeViewEx control.
///
/// The source of the event.
/// The instance containing the event data.
private void TreeViewEx_SizeChanged(object sender, EventArgs e)
{
this.Refresh();
}
///
/// Handles the NodeMouseClick event of the TreeViewEx control.
///
/// The source of the event.
/// The instance containing the event data.
private void TreeViewEx_NodeMouseClick(object sender, TreeNodeMouseClickEventArgs e)
{
try
{
if (e.Node != null)
{
if (e.Node.Nodes.Count > 0)
{
if (e.Node.IsExpanded)
{
e.Node.Collapse();
}
else
{
e.Node.Expand();
}
}
if (base.SelectedNode != null)
{
if (base.SelectedNode == e.Node && e.Node.IsExpanded)
{
if (!this._parentNodeCanSelect)
{
if (e.Node.Nodes.Count > 0)
{
base.SelectedNode = e.Node.Nodes[0];
}
}
}
}
}
}
catch (Exception ex)
{
throw ex;
}
}
///
/// Handles the DrawNode event of the treeview control.
///
/// The source of the event.
/// The instance containing the event data.
private void treeview_DrawNode(object sender, DrawTreeNodeEventArgs e)
{
try
{
if (e.Node == null || !this._isShowByCustomModel || (e.Node.Bounds.Width <= 0 && e.Node.Bounds.Height <= 0 && e.Node.Bounds.X <= 0 && e.Node.Bounds.Y <= 0))
{
e.DrawDefault = true;
}
else
{
e.Graphics.SetGDIHigh();
if (base.Nodes.IndexOf(e.Node) == 0)
{
this.blnHasVBar = this.IsVerticalScrollBarVisible();
}
Font font = e.Node.NodeFont;
if (font == null)
{
font = ((TreeView)sender).Font;
}
if (this.treeFontSize == SizeF.Empty)
{
this.treeFontSize = this.GetFontSize(font, e.Graphics);
}
bool flag = false;
int intLeft = 0;
if (CheckBoxes)
{
intLeft = 20;
}
int num = 0;
if (base.ImageList != null && base.ImageList.Images.Count > 0 && e.Node.ImageIndex >= 0 && e.Node.ImageIndex < base.ImageList.Images.Count)
{
flag = true;
num = (e.Bounds.Height - base.ImageList.ImageSize.Height) / 2;
intLeft += base.ImageList.ImageSize.Width;
}
intLeft += e.Node.Level * Indent;
if ((e.State == TreeNodeStates.Selected || e.State == TreeNodeStates.Focused || e.State == (TreeNodeStates.Focused | TreeNodeStates.Selected)) && (this._parentNodeCanSelect || e.Node.Nodes.Count <= 0))
{
e.Graphics.FillRectangle(new SolidBrush(this.m_nodeSelectedColor), new Rectangle(new Point(0, e.Node.Bounds.Y), new Size(base.Width, e.Node.Bounds.Height)));
e.Graphics.DrawString(e.Node.Text, font, new SolidBrush(this.m_nodeSelectedForeColor), (float)e.Bounds.X + intLeft, (float)e.Bounds.Y + ((float)this._nodeHeight - this.treeFontSize.Height) / 2f);
}
else
{
e.Graphics.FillRectangle(new SolidBrush(this._nodeBackgroundColor), new Rectangle(new Point(0, e.Node.Bounds.Y), new Size(base.Width, e.Node.Bounds.Height)));
e.Graphics.DrawString(e.Node.Text, font, new SolidBrush(this._nodeForeColor), (float)e.Bounds.X + intLeft, (float)e.Bounds.Y + ((float)this._nodeHeight - this.treeFontSize.Height) / 2f);
}
if (CheckBoxes)
{
Rectangle rectCheck = new Rectangle(e.Bounds.X + 3 + e.Node.Level * Indent, e.Bounds.Y + (e.Bounds.Height - 16) / 2, 16, 16);
GraphicsPath pathCheck = rectCheck.CreateRoundedRectanglePath(3);
e.Graphics.FillPath(new SolidBrush(Color.FromArgb(247, 247, 247)), pathCheck);
if (e.Node.Checked)
{
e.Graphics.DrawLines(new Pen(new SolidBrush(m_nodeSelectedColor),2), new Point[]
{
new Point(rectCheck.Left+2,rectCheck.Top+8),
new Point(rectCheck.Left+6,rectCheck.Top+12),
new Point(rectCheck.Right-4,rectCheck.Top+4)
});
}
e.Graphics.DrawPath(new Pen(new SolidBrush(Color.FromArgb(200, 200, 200))), pathCheck);
}
if (flag)
{
int num2 = e.Bounds.X - num - base.ImageList.ImageSize.Width;
if (num2 < 0)
{
num2 = 3;
}
e.Graphics.DrawImage(base.ImageList.Images[e.Node.ImageIndex], new Rectangle(new Point(num2 + intLeft - base.ImageList.ImageSize.Width, e.Bounds.Y + num), base.ImageList.ImageSize));
}
if (this._nodeIsShowSplitLine)
{
e.Graphics.DrawLine(new Pen(this._nodeSplitLineColor, 1f), new Point(0, e.Bounds.Y + this._nodeHeight - 1), new Point(base.Width, e.Bounds.Y + this._nodeHeight - 1));
}
bool flag2 = false;
if (e.Node.Nodes.Count > 0)
{
if (e.Node.IsExpanded && this._nodeUpPic != null)
{
e.Graphics.DrawImage(this._nodeUpPic, new Rectangle(base.Width - (this.blnHasVBar ? 50 : 30), e.Bounds.Y + (this._nodeHeight - 20) / 2, 20, 20));
}
else if (this._nodeDownPic != null)
{
e.Graphics.DrawImage(this._nodeDownPic, new Rectangle(base.Width - (this.blnHasVBar ? 50 : 30), e.Bounds.Y + (this._nodeHeight - 20) / 2, 20, 20));
}
flag2 = true;
}
if (this._isShowTip && this._lstTips.ContainsKey(e.Node.Name) && !string.IsNullOrWhiteSpace(this._lstTips[e.Node.Name]))
{
int num3 = base.Width - (this.blnHasVBar ? 50 : 30) - (flag2 ? 20 : 0);
int num4 = e.Bounds.Y + (this._nodeHeight - 20) / 2;
e.Graphics.DrawImage(this._tipImage, new Rectangle(num3, num4, 20, 20));
SizeF sizeF = e.Graphics.MeasureString(this._lstTips[e.Node.Name], this._tipFont, 100, StringFormat.GenericTypographic);
e.Graphics.DrawString(this._lstTips[e.Node.Name], this._tipFont, new SolidBrush(Color.White), (float)(num3 + 10) - sizeF.Width / 2f - 3f, (float)(num4 + 10) - sizeF.Height / 2f);
}
}
}
catch (Exception ex)
{
throw ex;
}
}
///
/// Gets the size of the font.
///
/// The font.
/// The g.
/// SizeF.
private SizeF GetFontSize(Font font, Graphics g = null)
{
SizeF result;
try
{
bool flag = false;
if (g == null)
{
g = base.CreateGraphics();
flag = true;
}
SizeF sizeF = g.MeasureString("a", font, 100, StringFormat.GenericTypographic);
if (flag)
{
g.Dispose();
}
result = sizeF;
}
catch (Exception ex)
{
throw ex;
}
return result;
}
///
/// Gets the window long.
///
/// The HWND.
/// Index of the n.
/// System.Int32.
[DllImport("user32", CharSet = CharSet.Auto)]
private static extern int GetWindowLong(IntPtr hwnd, int nIndex);
///
/// Determines whether [is vertical scroll bar visible].
///
/// true if [is vertical scroll bar visible]; otherwise, false.
private bool IsVerticalScrollBarVisible()
{
return base.IsHandleCreated && (TreeViewEx.GetWindowLong(base.Handle, -16) & 2097152) != 0;
}
}
}