using System; using System.Collections.Generic; using System.ComponentModel; using System.Drawing; using System.Data; using System.Linq; using System.Text; using System.Threading.Tasks; using System.Windows.Forms; using System.Drawing.Drawing2D; using System.Threading; namespace TemuKJD.UserComponent { /// /// 基于树视图的任务控件 /// public partial class UcTreeView : TreeView { #region //construckor /// /// 自定义树视图控件构造函数 /// public UcTreeView() { FullRowSelect = true; ShowLines = true; // 开启双缓冲等 this.SetStyle(ControlStyles.OptimizedDoubleBuffer | ControlStyles.EnableNotifyMessage | ControlStyles.ResizeRedraw | ControlStyles.AllPaintingInWmPaint, true); this.DrawMode = TreeViewDrawMode.OwnerDrawAll; this.ItemHeight = 32; this.ShowLines = true; this.AfterExpand += UserTreeView_AfterExpand; this.AfterSelect += UserTreeView_AfterSelect; this.Layout += UserTreeView_Layout; if (Properties.Resources.ResourceManager.GetObject("tree_default_icon_select") != null) defaultNodeImageSelect = (Bitmap)Properties.Resources.ResourceManager.GetObject("tree_default_icon_select"); if (Properties.Resources.ResourceManager.GetObject("tree_default_icon") != null) defaultNodeImage = (Bitmap)Properties.Resources.ResourceManager.GetObject("tree_default_icon"); } protected override void OnNotifyMessage(Message m) { if (m.Msg != 0x14) { base.OnNotifyMessage(m); } } protected override CreateParams CreateParams { get { CreateParams cp = base.CreateParams; cp.ExStyle |= 0x02000000; return cp; } } private void UserTreeView_AfterSelect(object sender, TreeViewEventArgs e) { if (e.Node.Parent != null) dicSelectNodeId[e.Node.Parent] = e.Node; } #endregion #region //event // 定义委托 public delegate void NodeGroupClickHandle(object sender, TreeViewEventArgs e); // 定义事件 public event NodeGroupClickHandle NodeGroupClick; // 执行事件 protected virtual void OnNodeGroupClick(TreeViewEventArgs e) { if (NodeGroupClick != null) { NodeGroupClick(this, e); } } private void UserTreeView_Layout(object sender, LayoutEventArgs e) { if (!DesignMode) { foreach (TreeNode node in this.Nodes) { if (node != null) { if (allNodes.Contains(node) == false) allNodes.Add(node); } foreach (TreeNode childNode in node.Nodes) { if (node == null) continue; if (!dicNodeImageSelect.Keys.Contains(childNode)) { // 获取图标 if (Properties.Resources.ResourceManager.GetObject("tree_" + childNode.Text + "_select") != null) { var bitmap = (Bitmap)Properties.Resources.ResourceManager.GetObject("tree_" + childNode.Text + "_select"); dicNodeImageSelect[childNode] = bitmap; } } if (!dicNodeImage.Keys.Contains(childNode)) { // 获取图标 if (Properties.Resources.ResourceManager.GetObject("tree_" + childNode.Text) != null) { var bitmap = (Bitmap)Properties.Resources.ResourceManager.GetObject("tree_" + childNode.Text); dicNodeImage[childNode] = bitmap; } } } } } } private void UserTreeView_AfterExpand(object sender, TreeViewEventArgs e) { BeginUpdate(); if (HideCollapsedGroup && !DesignMode) { for (int i = 0; i < this.Nodes.Count; i++) { if (e.Node != this.Nodes[i]) { this.Nodes.Remove(this.Nodes[i]); i--; } } } foreach (TreeNode node in this.AllNodes) { if (node == null) continue; if (node != e.Node) { node.Collapse(true); } else { if (this.SelectedNode == null || this.SelectedNode.Parent == node) continue; else if (dicSelectNodeId.Keys.Contains(node)) this.SelectedNode = dicSelectNodeId[node]; else if (node.Nodes.Count > 0) this.SelectedNode = node.Nodes[0]; } } EndUpdate(); } #endregion #region //field & property private Bitmap defaultNodeImage; private Bitmap defaultNodeImageSelect; private List lstTreeNode = new List(); private Dictionary dicSelectNodeId = new Dictionary(); private Dictionary dicNodeImage = new Dictionary(); private Dictionary dicNodeImageSelect = new Dictionary(); /// /// 展开按扭的大小 /// private Size ExpandButtonSize = new Size(16, 16); private Color _ExpandButtonColor = Color.FromArgb(255, 255, 255); /// /// 展开按扭颜色 /// [Description("展开按扭颜色"), Category("UserProperty")] public Color ExpandButtonColor { get { return _ExpandButtonColor; } set { if (_ExpandButtonColor != value) { _ExpandButtonColor = value; this.Invalidate(); } } } private Color _GroupBgColor = Color.FromArgb(249, 249, 249); /// /// 分组栏背景色 /// [Description("分组栏背景色"), Category("UserProperty")] public Color GroupBgColor { get { return _GroupBgColor; } set { if (_GroupBgColor != value) { _GroupBgColor = value; this.Invalidate(); } } } private Color _ChildNodeSelectedBgColor = Color.FromArgb(34, 148, 203); /// /// 子节点选中背景色 /// [Description("子节点选中背景色"), Category("UserProperty")] public Color ChildNodeSelectedBgColor { get { return this._ChildNodeSelectedBgColor; } set { if (_ChildNodeSelectedBgColor != value) { _ChildNodeSelectedBgColor = value; this.Invalidate(); } } } private Color _GroupTitleColor = Color.FromArgb(80, 80, 80); /// /// 分组栏标题色 /// [Description("分组栏标题色"), Category("UserProperty")] public Color GroupTitleColor { get { return _GroupTitleColor; } set { if (_GroupTitleColor != value) { _GroupTitleColor = value; this.Invalidate(); } } } private Color _OverForeColor = Color.FromArgb(235, 235, 235); /// /// 鼠标悬停色 /// [Description("鼠标悬停色"), Category("UserProperty")] public Color OverForeColor { get { return _OverForeColor; } set { if (_OverForeColor != value) { _OverForeColor = value; this.Invalidate(); } } } private Font groupFont = new Font("宋体", 10.5f); /// /// 组标题字体样式 /// [Description("组标题字体样式"), Category("UserProperty")] public Font GroupFont { get { return groupFont; } set { if (groupFont != value) { groupFont = value; this.Invalidate(); } } } private bool _HideCollpasedGroup = false; [Description("隐藏折叠的组"), Category("UserProperty")] public bool HideCollapsedGroup { get { return _HideCollpasedGroup; } set { if (_HideCollpasedGroup != value) { _HideCollpasedGroup = value; this.Invalidate(); } } } /// /// 节点高度 /// public new int ItemHeight { get { return base.ItemHeight; } set { if (base.ItemHeight != value && value >= 20) { base.ItemHeight = value; this.Invalidate(); } } } private List allNodes = new List(); /// /// 所有节点列表 /// public List AllNodes { get { return allNodes; } } #endregion #region //override protected override void OnDrawNode(DrawTreeNodeEventArgs e) { //base.OnDrawNode(e); DrawNodeItem(e); } protected override void WndProc(ref Message m) { if (m.Msg == 0x0201)//单击 { int wparam = m.LParam.ToInt32(); Point point = new Point( LOWORD(wparam), HIWORD(wparam)); //point = PointToClient(point); TreeNode tn = this.GetNodeAt(point); if (tn == null) { base.WndProc(ref m); return; } if (tn.Level == 0) { if (tn.IsExpanded) { //tn.Collapse(); } else { tn.Expand(); } m.Result = IntPtr.Zero; OnNodeGroupClick(new TreeViewEventArgs(tn, TreeViewAction.ByMouse)); return; } else { base.WndProc(ref m); //tn.IsSelected = true; //this.SelectedNode = tn; } this.SelectedNode = tn; } else if (m.Msg == 0x0203)//双击 { int wparam = m.LParam.ToInt32(); Point point = new Point( LOWORD(wparam), HIWORD(wparam)); //point = PointToClient(point); TreeNode tn = this.GetNodeAt(point); if (tn == null) { base.WndProc(ref m); return; } if (tn.Level == 0) { m.Result = IntPtr.Zero; return; } else { base.WndProc(ref m); } this.SelectedNode = tn; } else if (m.Msg == 0x0200)//鼠标移动 { try { int wparam = m.LParam.ToInt32(); Point point = new Point( LOWORD(wparam), HIWORD(wparam)); //point = PointToClient(point); TreeNode tn = this.GetNodeAt(point); if (tn == null) { Cursor = Cursors.Default; // this.SelectedNode = null; base.WndProc(ref m); return; } Cursor = Cursors.Hand; //this.SelectedNode = tn; } catch { } } else if (m.Msg == 0x02A3)//鼠标移出 WM_MOUSELEAVE = $02A3; { // this.SelectedNode = null; base.WndProc(ref m); return; } else { base.WndProc(ref m); } //WM_LBUTTONDOWN = $0201 //WM_LBUTTONDBLCLK = $0203; } #endregion #region //private method /// /// 自定义绘制节点 /// /// private void DrawNodeItem(DrawTreeNodeEventArgs e) { TreeNode tn = e.Node; if (tn.Level == 0) { using (Graphics g = e.Graphics) { //g.Clear(this.BackColor); // 清空画布,完整重绘时才能使用 //g.SmoothingMode = SmoothingMode.HighQuality; // 高质量 //g.PixelOffsetMode = PixelOffsetMode.HighQuality; // 高像素偏移质量 //绘制分组的背景 //RenderBackgroundInternalRate(g, // e.Bounds, // GroupBgColor, // GroupBgColor, // Color.FromArgb(200, 255, 255, 255), // 0.45f, // true, // 300); int red = GroupBgColor.R; int green = GroupBgColor.G; int blue = GroupBgColor.B; if (red < 127) red += 15; else red -= 15; if (green < 127) green += 15; else green -= 15; if (blue < 127) blue += 15; else blue -= 15; var color = Color.FromArgb(red, green, blue); RenderBackgroundSolid(g, e.Bounds, color, color, color, false); //绘制展开按扭 //g.FillEllipse(new SolidBrush(ExpandButtonColor), ExpandButtonBounds(e.Bounds)); //g.DrawEllipse(new Pen(Color.LightGray), ExpandButtonBounds(e.Bounds)); //Point p1; //Point p2; //Point p3; //if (tn.IsExpanded) //{ // p1 = new Point(ExpandButtonBounds(e.Bounds).X + 3, ExpandButtonBounds(e.Bounds).Bottom - 4); // p2 = new Point(ExpandButtonBounds(e.Bounds).X + (ExpandButtonSize.Width) / 2, ExpandButtonBounds(e.Bounds).Top + 5); // p3 = new Point(ExpandButtonBounds(e.Bounds).Right - 3, ExpandButtonBounds(e.Bounds).Bottom - 4); //} //else //{ // p1 = new Point(ExpandButtonBounds(e.Bounds).X + 3, ExpandButtonBounds(e.Bounds).Y + 4); // p2 = new Point(ExpandButtonBounds(e.Bounds).X + (ExpandButtonSize.Width) / 2, ExpandButtonBounds(e.Bounds).Bottom - 5); // p3 = new Point(ExpandButtonBounds(e.Bounds).Right - 3, ExpandButtonBounds(e.Bounds).Y + 4); //} //GraphicsPath gp = new GraphicsPath(); //gp.AddLine(p1, p2); //gp.AddLine(p2, p3); //g.DrawPath(new Pen(Color.FromArgb(255, 150, 0, 0), 2f), gp); //绘制分组的文本 TextRenderer.DrawText(g, e.Node.Text, this.GroupFont, GroupTitleBounds(e.Bounds), this.GroupTitleColor, TextFormatFlags.Left | TextFormatFlags.VerticalCenter | TextFormatFlags.EndEllipsis); } } else if (tn.Level == 1) { //e.DrawDefault = true; using (Graphics g = e.Graphics) { #region 小奶猫增加权限后,无法自动绘制TreeNode图标,经调试确认,增加此段代码 by ttzhao 2020.7.1 if (!dicNodeImageSelect.Keys.Contains(e.Node)) { // 获取图标 if (Properties.Resources.ResourceManager.GetObject(e.Node.Text + "_select") != null) { var bitmap = (Bitmap)Properties.Resources.ResourceManager.GetObject(e.Node.Text + "_select"); dicNodeImageSelect[e.Node] = bitmap; } } if (!dicNodeImage.Keys.Contains(e.Node)) { // 获取图标 if (Properties.Resources.ResourceManager.GetObject(e.Node.Text) != null) { var bitmap = (Bitmap)Properties.Resources.ResourceManager.GetObject(e.Node.Text); dicNodeImage[e.Node] = bitmap; } } #endregion 小奶猫增加权限后,无法自动绘制TreeNode图标,经调试确认,增加此段代码 by ttzhao 2020.7.1 if (tn.IsSelected) { RenderBackgroundSolid(g, e.Bounds, ChildNodeSelectedBgColor, ChildNodeSelectedBgColor, ChildNodeSelectedBgColor, false); //TextRenderer.DrawText(g, e.Node.Text, new Font(this.Font.FontFamily.Name, this.Font.Size, FontStyle.Underline), e.Bounds, OverForeColor, TextFormatFlags.Left | TextFormatFlags.VerticalCenter); TextRenderer.DrawText(g, e.Node.Text, this.Font, ChildTitleBounds(e.Bounds), this.OverForeColor, TextFormatFlags.Left | TextFormatFlags.VerticalCenter); // 绘制图标 if (dicNodeImageSelect.Keys.Contains(e.Node)) g.DrawImage(dicNodeImageSelect[e.Node], new Rectangle(e.Bounds.X + 30, e.Bounds.Y + 8, 16, 16)); else if (defaultNodeImageSelect != null) g.DrawImage(defaultNodeImageSelect, new Rectangle(e.Bounds.X + 30, e.Bounds.Y + 8, 16, 16)); } else { RenderBackgroundSolid(g, e.Bounds, GroupBgColor, GroupBgColor, GroupBgColor, false); //TextRenderer.DrawText(g, e.Node.Text, this.Font, e.Bounds, this.ForeColor, TextFormatFlags.Left | TextFormatFlags.VerticalCenter); TextRenderer.DrawText(g, e.Node.Text, this.Font, ChildTitleBounds(e.Bounds), this.ForeColor, TextFormatFlags.Left | TextFormatFlags.VerticalCenter); // 绘制图标 if (dicNodeImage.Keys.Contains(e.Node)) g.DrawImage(dicNodeImage[e.Node], new Rectangle(e.Bounds.X + 30, e.Bounds.Y + 8, 16, 16)); else if (defaultNodeImage != null) g.DrawImage(defaultNodeImage, new Rectangle(e.Bounds.X + 30, e.Bounds.Y + 8, 16, 16)); } } } } /// /// 展开按扭区域 一级菜单后面的展开按钮 /// /// /// private Rectangle ExpandButtonBounds(Rectangle childRect) { Rectangle lrect = new Rectangle(new Point(childRect.Right - ExpandButtonSize.Width * 3 / 2, (childRect.Height - ExpandButtonSize.Height) / 2 + childRect.Top), ExpandButtonSize); return lrect; } /// /// 取得分组标题绘制空间 一级菜单 /// /// /// private Rectangle GroupTitleBounds(Rectangle childRect) { Rectangle lrect = childRect; lrect.Width -= ExpandButtonSize.Width * 3 / 2 + 20; //lrect.Offset(45, 0); lrect.Offset(12, 0); return lrect; } private Rectangle ChildTitleBounds(Rectangle rect) { Rectangle lrect = rect; lrect.Width -= 50; lrect.Offset(55, 0); return lrect; } #endregion #region //draw internal void RenderBackgroundSolid(Graphics g, Rectangle rect, Color baseColor, Color borderColor, Color innerBorderColor, bool drawBorder) { if (drawBorder) { rect.Width--; rect.Height--; } using (SolidBrush brush = new SolidBrush(baseColor)) { g.FillRectangle(brush, rect); } if (drawBorder) { using (Pen pen = new Pen(borderColor)) { g.DrawRectangle(pen, rect); } rect.Inflate(-1, -1); using (Pen pen = new Pen(innerBorderColor)) { g.DrawRectangle(pen, rect); } } } internal void RenderBackgroundInternal(Graphics g, Rectangle rect, Color baseColor, Color borderColor, Color innerBorderColor, float basePosition, bool drawBorder, LinearGradientMode mode) { if (drawBorder) { rect.Width--; rect.Height--; } using (LinearGradientBrush brush = new LinearGradientBrush(rect, Color.Transparent, Color.Transparent, mode)) { Color[] colors = new Color[4]; colors[0] = GetColor(baseColor, 0, 35, 24, 9); colors[1] = GetColor(baseColor, 0, 13, 8, 3); colors[2] = baseColor; colors[3] = GetColor(baseColor, 0, 68, 69, 54); ColorBlend blend = new ColorBlend(); blend.Positions = new float[] { 0.0f, basePosition, basePosition + 0.05f, 1.0f }; blend.Colors = colors; brush.InterpolationColors = blend; g.FillRectangle(brush, rect); } if (baseColor.A > 80) { Rectangle rectTop = rect; if (mode == LinearGradientMode.Vertical) { rectTop.Height = (int)(rectTop.Height * basePosition); } else { rectTop.Width = (int)(rect.Width * basePosition); } using (SolidBrush brushAlpha = new SolidBrush(Color.FromArgb(80, 255, 255, 255))) { g.FillRectangle(brushAlpha, rectTop); } } if (drawBorder) { using (Pen pen = new Pen(borderColor)) { g.DrawRectangle(pen, rect); } rect.Inflate(-1, -1); using (Pen pen = new Pen(innerBorderColor)) { g.DrawRectangle(pen, rect); } } } internal void RenderBackgroundInternalRate(Graphics g, Rectangle rect, Color baseColor, Color borderColor, Color innerBorderColor, float basePosition, bool drawBorder, float rate) { if (drawBorder) { rect.Width--; rect.Height--; } using (LinearGradientBrush brush = new LinearGradientBrush(rect, Color.Transparent, Color.Transparent, rate)) { Color[] colors = new Color[4]; colors[0] = GetColor(baseColor, 0, 35, 24, 9); colors[1] = GetColor(baseColor, 0, 13, 8, 3); colors[2] = baseColor; colors[3] = GetColor(baseColor, 0, 68, 69, 54); ColorBlend blend = new ColorBlend(); blend.Positions = new float[] { 0.0f, basePosition, basePosition + 0.05f, 1.0f }; blend.Colors = colors; brush.InterpolationColors = blend; g.FillRectangle(brush, rect); } if (baseColor.A > 80) { Rectangle rectTop = rect; if (true/*mode == LinearGradientMode.Vertical*/) { rectTop.Height = (int)(rectTop.Height * basePosition); } else { rectTop.Width = (int)(rect.Width * basePosition); } using (SolidBrush brushAlpha = new SolidBrush(Color.FromArgb(80, 255, 255, 255))) { g.FillRectangle(brushAlpha, rectTop); } } if (drawBorder) { using (Pen pen = new Pen(borderColor)) { g.DrawRectangle(pen, rect); } rect.Inflate(-1, -1); using (Pen pen = new Pen(innerBorderColor)) { g.DrawRectangle(pen, rect); } } } private Color GetColor(Color colorBase, int a, int r, int g, int b) { int a0 = colorBase.A; int r0 = colorBase.R; int g0 = colorBase.G; int b0 = colorBase.B; if (a + a0 > 255) { a = 255; } else { a = a + a0; } if (r + r0 > 255) { r = 255; } else { r = r + r0; } if (g + g0 > 255) { g = 255; } else { g = g + g0; } if (b + b0 > 255) { b = 255; } else { b = b + b0; } return Color.FromArgb(a, r, g, b); } private Color GetColor2(Color colorBase, int a, int r, int g, int b) { int a0 = colorBase.A; int r0 = colorBase.R; int g0 = colorBase.G; int b0 = colorBase.B; if (a + a0 > 255) { a = 255; } else { a = a + a0; } if (r0 - r < 0) { r = 0; } else { r = r0 - r; } if (g0 - g < 0) { g = 0; } else { g = g0 - g; } if (b0 - b < 0) { b = 0; } else { b = b0 - b; } return Color.FromArgb(a, r, g, b); } #endregion public static int LOWORD(int value) { return value & 0xFFFF; } public static int HIWORD(int value) { return value >> 16; } public void ExpandGroup(string groupName) { var node = this.AllNodes.FirstOrDefault(n => n.Name == groupName); if (node == null) return; BeginUpdate(); if (!this.Nodes.Contains(node)) this.Nodes.Insert(0, node); node.Expand(); EndUpdate(); } } }