using System;
|
using System.Collections.Generic;
|
using System.ComponentModel;
|
using System.Drawing;
|
using System.Drawing.Drawing2D;
|
using System.Runtime.InteropServices;
|
using System.Windows.Forms;
|
using DPumpHydr.WinFrmUI.WenSkin.Properties;
|
|
namespace DPumpHydr.WinFrmUI.WenSkin.Controls
|
{
|
public partial class TreeViewEx : TreeView
|
{
|
#region 私有属性
|
|
private const int WS_VSCROLL = 2097152;
|
private const int GWL_STYLE = -16;
|
private static readonly Font font = new Font("Arial Unicode MS", 12f);
|
private int _nodeHeight = 50;
|
private SizeF treeFontSize = SizeF.Empty;
|
private bool blnHasVBar = false;
|
private Color nodeForeColor = Color.White;
|
|
#endregion
|
|
#region 公有属性
|
public Dictionary<string, string> LstTips { get; set; } = new Dictionary<string, string>();
|
[Category("自定义属性"), Description("角标文字字体")]
|
public Font TipFont { get; set; } = font;
|
[Category("自定义属性"), Description("是否显示角标")]
|
public Image TipImage { get; set; } = Resources.tips;
|
[Category("自定义属性"), Description("是否显示角标")]
|
public bool IsShowTip { get; set; } = false;
|
[Category("自定义属性"), Description("使用自定义模式")]
|
public bool IsShowByCustomModel { get; set; } = true;
|
[Category("自定义属性"), Description("节点高度(IsShowByCustomModel=true时生效)")]
|
public int NodeHeight
|
{
|
get
|
{
|
return this._nodeHeight;
|
}
|
set
|
{
|
this._nodeHeight = value;
|
base.ItemHeight = value;
|
}
|
}
|
[Category("自定义属性"), Description("下翻图标(IsShowByCustomModel=true时生效)")]
|
public Image NodeDownPic { get; set; } = Resources.list_add;
|
[Category("自定义属性"), Description("上翻图标(IsShowByCustomModel=true时生效)")]
|
public Image NodeUpPic { get; set; } = Resources.list_subtract;
|
[Category("自定义属性"), Description("节点背景颜色(IsShowByCustomModel=true时生效)")]
|
public Color NodeBackgroundColor { get; set; } = Color.White;
|
[Category("自定义属性"), Description("节点字体颜色(IsShowByCustomModel=true时生效)"),DefaultValue(typeof(Color),"White")]
|
public Color NodeForeColor { get => nodeForeColor; set { base.ForeColor = value; nodeForeColor = value; } }
|
[Category("自定义属性"), Description("节点是否显示分割线(IsShowByCustomModel=true时生效)")]
|
public bool NodeIsShowSplitLine { get; set; } = false;
|
[Category("自定义属性"), Description("节点分割线颜色(IsShowByCustomModel=true时生效)")]
|
public Color NodeSplitLineColor { get; set; } = Color.FromArgb(232, 232, 232);
|
[Category("自定义属性"), Description("选中节点背景颜色(IsShowByCustomModel=true时生效)")]
|
public Color NodeSelectedColor { get; set; } = Color.FromArgb(255, 77, 59);
|
[Category("自定义属性"), Description("选中节点字体颜色(IsShowByCustomModel=true时生效)")]
|
public Color NodeSelectedForeColor { get; set; } = Color.White;
|
[Category("自定义属性"), Description("父节点是否可选中")]
|
public bool ParentNodeCanSelect { get; set; } = true;
|
#endregion
|
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.FromArgb(37, 37, 38);
|
this.BorderStyle = System.Windows.Forms.BorderStyle.None;
|
DoubleBuffered = true;
|
ForeColor = Color.White;
|
}
|
|
protected override void WndProc(ref Message m)
|
{
|
|
if (m.Msg == 0x0014) // 禁掉清除背景消息WM_ERASEBKGND
|
|
return;
|
|
base.WndProc(ref m);
|
|
}
|
#region 重画
|
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;
|
}
|
}
|
private void TreeViewEx_SizeChanged(object sender, EventArgs e)
|
{
|
this.Refresh();
|
}
|
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;
|
}
|
}
|
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.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.NodeSelectedForeColor), (float)e.Bounds.X + intLeft, (float)e.Bounds.Y + ((float)this._nodeHeight - this.treeFontSize.Height) / 2f);
|
}
|
else
|
{
|
//非选中状态画背景和文字
|
e.Graphics.FillRectangle(new SolidBrush(e.Node.BackColor), 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(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(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;
|
}
|
}
|
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;
|
}
|
[DllImport("user32", CharSet = CharSet.Auto)]
|
private static extern int GetWindowLong(IntPtr hwnd, int nIndex);
|
private bool IsVerticalScrollBarVisible()
|
{
|
return base.IsHandleCreated && (TreeViewEx.GetWindowLong(base.Handle, -16) & 2097152) != 0;
|
}
|
#endregion
|
|
#region 鼠标移动事件
|
|
private TreeNode mouseNode;
|
|
protected override void OnMouseMove(MouseEventArgs e)
|
{
|
base.OnMouseMove(e);
|
TreeNode node = this.GetNodeAt(e.X, e.Y);
|
if (node != mouseNode)
|
{
|
if (mouseNode != null)
|
mouseNode.BackColor = Color.Transparent;
|
node.BackColor = Color.FromArgb(51, 51, 52);
|
mouseNode = node;
|
}
|
}
|
protected override void OnMouseLeave(EventArgs e)
|
{
|
base.OnMouseLeave(e);
|
if (mouseNode is null)
|
return;
|
mouseNode.BackColor = Color.Transparent;
|
mouseNode = null;
|
}
|
|
#endregion
|
}
|
}
|