前提
入行已经7,8年了,一直想做一套漂亮点的自定义控件,于是就有了本系列文章。
GitHub:https://github.com/kwwwvagaa/NetWinformControl
码云:https://gitee.com/kwwwvagaa/net_winform_custom_control.git
如果觉得写的还行,请点个 star 支持一下吧
欢迎前来交流探讨: 企鹅群568015492
麻烦博客下方点个【推荐】,谢谢
NuGet
Install-Package HZH_Controls
目录
https://www.cnblogs.com/bfyx/p/11364884.html
用处及效果
准备工作
依然是用GDI+画的,不懂的可以先百度一下
开始
添加一个实体类,用以记录数据源节点信息
1 public class MindMappingItemEntity 2 { 3 ///4 /// Gets or sets the identifier. 5 /// 6 /// The identifier. 7 public string ID { get; set; } 8 private string _text; 9 /// 10 /// Gets or sets the text. 11 /// 12 /// The text. 13 public string Text 14 { 15 get { return _text; } 16 set 17 { 18 _text = value; 19 ResetSize(); 20 } 21 } 22 /// 23 /// Gets or sets the data source. 24 /// 25 /// The data source. 26 public object DataSource { get; set; } 27 /// 28 /// The childrens 29 /// 30 private MindMappingItemEntity[] _Childrens; 31 /// 32 /// Gets or sets the childrens. 33 /// 34 /// The childrens. 35 public MindMappingItemEntity[] Childrens 36 { 37 get { return _Childrens; } 38 set 39 { 40 _Childrens = value; 41 if (value != null && value.Length > 0) 42 { 43 value.ToList().ForEach(p => { if (p != null) { p.ParentItem = this; } }); 44 } 45 } 46 } 47 /// 48 /// The back color 49 /// 50 private Color backColor = Color.Transparent; 51 52 /// 53 /// Gets or sets the color of the back. 54 /// 55 /// The color of the back. 56 public Color BackColor 57 { 58 get { return backColor; } 59 set { backColor = value; } 60 } 61 62 private Font font = new Font("微软雅黑", 10); 63 64 public Font Font 65 { 66 get { return font; } 67 set 68 { 69 font = value; 70 ResetSize(); 71 } 72 } 73 74 /// 75 /// The fore color 76 /// 77 private Color foreColor = Color.Black; 78 79 /// 80 /// Gets or sets the color of the fore. 81 /// 82 /// The color of the fore. 83 public Color ForeColor 84 { 85 get { return foreColor; } 86 set { foreColor = value; } 87 } 88 private bool _IsExpansion = false; 89 /// 90 /// Gets or sets a value indicating whether the instance is expanded. 91 /// 92 /// true if this instance is expansion; otherwise, false. 93 public bool IsExpansion 94 { 95 get 96 { 97 return _IsExpansion; 98 } 99 set 100 { 101 if (value == _IsExpansion) 102 return; 103 _IsExpansion = value; 104 if (!value) 105 { 106 _Childrens.ToList().ForEach(p => { if (p != null) { p.IsExpansion = false; } }); 107 } 108 109 } 110 } 111 112 /// 113 /// Gets the parent item. 114 /// 115 /// The parent item. 116 public MindMappingItemEntity ParentItem { get; private set; } 117 /// 118 /// Gets all childrens maximum show count. 119 /// 120 /// All childrens maximum show count. 121 public int AllChildrensMaxShowHeight { get { return GetAllChildrensMaxShowHeight(); } } 122 /// 123 /// Gets the maximum level. 124 /// 125 /// The maximum level. 126 public int AllChildrensMaxShowWidth { get { return GetAllChildrensMaxShowWidth(); } } 127 128 /// 129 /// Gets all childrens maximum show count. 130 /// 131 /// System.Int32. 132 private int GetAllChildrensMaxShowHeight() 133 { 134 if (!_IsExpansion || _Childrens == null || _Childrens.Length <= 0) 135 return ItemHeight + 10; 136 else 137 { 138 return _Childrens.Sum(p => p == null ? 0 : p.AllChildrensMaxShowHeight); 139 } 140 } 141 /// 142 /// Gets the maximum level. 143 /// 144 /// System.Int32. 145 private int GetAllChildrensMaxShowWidth() 146 { 147 if (!_IsExpansion || _Childrens == null || _Childrens.Length <= 0) 148 return ItemWidth + 50; 149 else 150 { 151 return 1 + _Childrens.Max(p => p == null ? 0 : p.AllChildrensMaxShowWidth); 152 } 153 } 154 /// 155 /// Gets or sets the working rectangle. 156 /// 157 /// The working rectangle. 158 internal RectangleF WorkingRectangle { get; set; } 159 /// 160 /// Gets or sets the draw rectangle. 161 /// 162 /// The draw rectangle. 163 internal RectangleF DrawRectangle { get; set; } 164 /// 165 /// Gets or sets the expansion rectangle. 166 /// 167 /// The expansion rectangle. 168 internal RectangleF ExpansionRectangle { get; set; } 169 /// 170 /// Gets the height of the item. 171 /// 172 /// The height of the item. 173 private int ItemHeight { private get; private set; } 174 /// 175 /// Gets the width of the item. 176 /// 177 /// The width of the item. 178 private int ItemWidth { private get; private set; } 179 /// 180 /// Resets the size. 181 /// 182 private void ResetSize() 183 { 184 string _t = _text; 185 if (string.IsNullOrEmpty(_t)) 186 { 187 _t = "aaaa"; 188 } 189 Bitmap bit = new Bitmap(1, 1); 190 var g = Graphics.FromImage(bit); 191 var size = g.MeasureString(_t, font); 192 g.Dispose(); 193 bit.Dispose(); 194 ItemHeight = (int)size.Height; 195 ItemWidth = (int)size.Width; 196 } 197 }
主要属性说明:
Text:显示文字
Childrens:子节点信息
BackColor:节点颜色
IsExpansion:是否展开子节点
ParentItem:父级节点
AllChildrensMaxShowHeight:该节点包含所有子节点需要显示的高度,通过私有函数GetAllChildrensMaxShowHeight()返回结果
AllChildrensMaxShowWidth:该节点包含所有子节点需要显示的宽度,通过私有函数GetAllChildrensMaxShowWidth()返回结果
WorkingRectangle:该节点以及所有子节点的工作区域
DrawRectangle:该节点的绘制区域
ExpansionRectangle:展开折叠按钮的绘制区域
ItemHeight:该节点的高度
ItemWidth:该节点的宽度
主要函数说明:
GetAllChildrensMaxShowHeight:获取当前节点及所有子节点需要的最大高度
GetAllChildrensMaxShowWidth:获取当前节点及所有子节点需要的最大宽度
ResetSize:当文本和字体改变时重新计算宽高
添加一个类UCMindMapping,继承UserControl
添加一些属性
1 ///2 /// The line color 3 /// 4 private Color lineColor = Color.Black; 5 6 /// 7 /// Gets or sets the color of the line. 8 /// 9 /// The color of the line. 10 [Description("线条颜色"), Category("自定义")] 11 public Color LineColor 12 { 13 get { return lineColor; } 14 set 15 { 16 lineColor = value; 17 Refresh(); 18 } 19 } 20 /// 21 /// The split width 22 /// 23 private int splitWidth = 50; 24 // private int itemHeight = 20; 25 /// 26 /// The padding 27 /// 28 private int padding = 20; 29 30 /// 31 /// The m rect working 32 /// 33 Rectangle m_rectWorking = Rectangle.Empty; 34 /// 35 /// Occurs when [item clicked]. 36 /// 37 public event EventHandler ItemClicked; 38 /// 39 /// The data source 40 /// 41 private MindMappingItemEntity dataSource; 42 /// 43 /// Gets or sets the data source. 44 /// 45 /// The data source. 46 [Description("数据源"), Category("自定义")] 47 public MindMappingItemEntity DataSource 48 { 49 get { return dataSource; } 50 set 51 { 52 dataSource = value; 53 54 ResetSize(); 55 } 56 }
一个辅助函数,用以在大小过数据改变时计算工作区域和位置
1 ///2 /// 重置大小 3 /// 4 private void ResetSize() 5 { 6 if (this.Parent == null) 7 return; 8 try 9 { 10 ControlHelper.FreezeControl(this, true); 11 if (dataSource == null) 12 { 13 m_rectWorking = Rectangle.Empty; 14 this.Size = this.Parent.Size; 15 } 16 else 17 { 18 int intWidth = dataSource.AllChildrensMaxShowWidth; 19 int intHeight = dataSource.AllChildrensMaxShowHeight; 20 this.Width = intWidth + padding * 2; 21 this.Height = intHeight + padding * 2; 22 if (this.Width < this.Parent.Width) 23 this.Width = this.Parent.Width; 24 m_rectWorking = new Rectangle(padding, padding, intWidth, intHeight); 25 if (this.Height > this.Parent.Height) 26 { 27 //this.Location = new Point(0, 0); 28 } 29 else 30 this.Location = new Point(0, (this.Parent.Height - this.Height) / 2); 31 } 32 } 33 finally 34 { 35 ControlHelper.FreezeControl(this, false); 36 } 37 }
重绘
1 ///2 /// 引发 事件。 3 /// 4 /// 包含事件数据的 。 5 protected override void OnPaint(PaintEventArgs e) 6 { 7 try 8 { 9 base.OnPaint(e); 10 if (m_rectWorking == Rectangle.Empty || m_rectWorking == null) 11 return; 12 var g = e.Graphics; 13 g.SetGDIHigh(); 14 15 int intHeight = dataSource.AllChildrensMaxShowHeight; 16 dataSource.WorkingRectangle = new RectangleF(m_rectWorking.Left, m_rectWorking.Top + (m_rectWorking.Height - intHeight) / 2, m_rectWorking.Width, intHeight); 17 18 DrawItem(dataSource, g); 19 } 20 catch (Exception exc) 21 { 22 MessageBox.Show(exc.ToString(), "错误"); 23 } 24 }
1 ///2 /// 画节点 3 /// 4 /// The item. 5 /// The g. 6 private void DrawItem(MindMappingItemEntity item, Graphics g) 7 { 8 //节点 9 var size = g.MeasureString(item.Text, item.Font); 10 item.DrawRectangle = new RectangleF(item.WorkingRectangle.Left + 2, item.WorkingRectangle.Top + (item.WorkingRectangle.Height - size.Height) / 2 + 2, size.Width + 4, size.Height + 4); 11 GraphicsPath drawPath = item.DrawRectangle.CreateRoundedRectanglePath(5); 12 g.FillPath(new SolidBrush(item.BackColor), drawPath); 13 g.DrawString(item.Text, item.Font, new SolidBrush(item.ForeColor), item.DrawRectangle.Location.X + 2, item.DrawRectangle.Location.Y + 2); 14 //子节点 15 if (item.Childrens != null && item.IsExpansion) 16 { 17 for (int i = 0; i < item.Childrens.Length; i++) 18 { 19 var child = item.Childrens[i]; 20 if (i == 0) 21 { 22 child.WorkingRectangle = new RectangleF(item.DrawRectangle.Right + splitWidth, item.WorkingRectangle.Top, item.WorkingRectangle.Width - (item.DrawRectangle.Width + splitWidth), child.AllChildrensMaxShowHeight); 23 } 24 else 25 { 26 child.WorkingRectangle = new RectangleF(item.DrawRectangle.Right + splitWidth, item.Childrens[i - 1].WorkingRectangle.Bottom, item.WorkingRectangle.Width - (item.DrawRectangle.Width + splitWidth), child.AllChildrensMaxShowHeight); 27 } 28 DrawItem(child, g); 29 } 30 } 31 //连线 32 if (item.ParentItem != null) 33 { 34 g.DrawLines(new Pen(new SolidBrush(lineColor), 1), new PointF[] 35 { 36 new PointF(item.ParentItem.DrawRectangle.Right,item.ParentItem.DrawRectangle.Top+item.ParentItem.DrawRectangle.Height/2), 37 new PointF(item.ParentItem.DrawRectangle.Right+12,item.ParentItem.DrawRectangle.Top+item.ParentItem.DrawRectangle.Height/2), 38 //new PointF(item.ParentItem.DrawRectangle.Right+12,item.DrawRectangle.Top+item.DrawRectangle.Height/2), 39 new PointF(item.DrawRectangle.Left-12,item.DrawRectangle.Top+item.DrawRectangle.Height/2), 40 new PointF(item.DrawRectangle.Left,item.DrawRectangle.Top+item.DrawRectangle.Height/2), 41 }); 42 } 43 //展开折叠按钮 44 if (item.Childrens != null && item.Childrens.Length > 0) 45 { 46 RectangleF _rect = new RectangleF(item.DrawRectangle.Right + 1, item.DrawRectangle.Top + (item.DrawRectangle.Height - 10) / 2, 10, 10); 47 item.ExpansionRectangle = _rect; 48 g.FillEllipse(new SolidBrush(this.BackColor), _rect); 49 g.DrawEllipse(new Pen(new SolidBrush(Color.Black)), _rect); 50 g.DrawLine(new Pen(new SolidBrush(lineColor)), _rect.Left + 2, _rect.Y + _rect.Height / 2, _rect.Right - 2, _rect.Y + _rect.Height / 2); 51 if (!item.IsExpansion) 52 { 53 g.DrawLine(new Pen(new SolidBrush(lineColor)), _rect.Left + _rect.Width / 2, _rect.Top + 2, _rect.Left + _rect.Width / 2, _rect.Bottom - 2); 54 } 55 } 56 }
控件的单击和双击时间来处理展开折叠事件
1 ///2 /// 双击处理,主要用于检测节点双击展开折叠 3 /// 4 /// The source of the event. 5 /// The instance containing the event data. 6 void UCMindMapping_DoubleClick(object sender, EventArgs e) 7 { 8 var mouseLocation = this.PointToClient(Control.MousePosition); 9 10 bool bln = CheckExpansionDoubleClick(dataSource, mouseLocation); 11 if (bln) 12 { 13 ResetSize(); 14 this.Parent.Refresh(); 15 } 16 } 17 18 /// 19 /// 单击处理,主要用于单击节点事件和,展开关闭圆圈处理 20 /// 21 /// The source of the event. 22 /// The instance containing the event data. 23 void UCMindMapping_Click(object sender, EventArgs e) 24 { 25 var mouseLocation = this.PointToClient(Control.MousePosition); 26 27 bool bln = CheckExpansionClick(dataSource, mouseLocation); 28 if (bln) 29 { 30 ResetSize(); 31 this.Parent.Refresh(); 32 } 33 }
1 ///2 /// 双击检查 3 /// 4 /// The item. 5 /// The mouse location. 6 /// true if XXXX, false otherwise. 7 private bool CheckExpansionDoubleClick(MindMappingItemEntity item, Point mouseLocation) 8 { 9 if (item == null) 10 return false; 11 else 12 { 13 if (item.DrawRectangle.Contains(mouseLocation)) 14 { 15 item.IsExpansion = !item.IsExpansion; 16 return true; 17 } 18 if (item.Childrens != null && item.Childrens.Length > 0) 19 { 20 foreach (var child in item.Childrens) 21 { 22 var bln = CheckExpansionDoubleClick(child, mouseLocation); 23 if (bln) 24 return bln; 25 } 26 } 27 } 28 return false; 29 } 30 31 /// 32 /// 单击检查 33 /// 34 /// The item. 35 /// The mouse location. 36 /// true if XXXX, false otherwise. 37 private bool CheckExpansionClick(MindMappingItemEntity item, Point mouseLocation) 38 { 39 if (item == null) 40 return false; 41 else 42 { 43 if (ItemClicked != null && item.WorkingRectangle.Contains(mouseLocation)) 44 { 45 ItemClicked(item, null); 46 } 47 else if (item.ExpansionRectangle.Contains(mouseLocation)) 48 { 49 item.IsExpansion = !item.IsExpansion; 50 return true; 51 } 52 if (item.Childrens != null && item.Childrens.Length > 0) 53 { 54 foreach (var child in item.Childrens) 55 { 56 var bln = CheckExpansionClick(child, mouseLocation); 57 if (bln) 58 return bln; 59 } 60 } 61 } 62 return false; 63 }
完整代码
1 // *********************************************************************** 2 // Assembly : HZH_Controls 3 // Created : 2019-09-11 4 // 5 // *********************************************************************** 6 //7 // Copyright by Huang Zhenghui(黄正辉) All, QQ group:568015492 QQ:623128629 Email:[email protected] 8 // 9 // 10 // Blog: https://www.cnblogs.com/bfyx 11 // GitHub:https://github.com/kwwwvagaa/NetWinformControl 12 // gitee:https://gitee.com/kwwwvagaa/net_winform_custom_control.git 13 // 14 // If you use this code, please keep this note. 15 // *********************************************************************** 16 using System; 17 using System.Collections.Generic; 18 using System.Linq; 19 using System.Text; 20 using System.Windows.Forms; 21 using System.Drawing; 22 using System.Drawing.Drawing2D; 23 using System.ComponentModel; 24 25 namespace HZH_Controls.Controls 26 { 27 /// 28 /// Class UCMindMapping. 29 /// Implements the 30 /// 31 /// 32 internal class UCMindMapping : UserControl 33 { 34 /// 35 /// The line color 36 /// 37 private Color lineColor = Color.Black; 38 39 /// 40 /// Gets or sets the color of the line. 41 /// 42 /// The color of the line. 43 [Description("线条颜色"), Category("自定义")] 44 public Color LineColor 45 { 46 get { return lineColor; } 47 set 48 { 49 lineColor = value; 50 Refresh(); 51 } 52 } 53 /// 54 /// The split width 55 /// 56 private int splitWidth = 50; 57 // private int itemHeight = 20; 58 /// 59 /// The padding 60 /// 61 private int padding = 20; 62 63 /// 64 /// The m rect working 65 /// 66 Rectangle m_rectWorking = Rectangle.Empty; 67 /// 68 /// Occurs when [item clicked]. 69 /// 70 public event EventHandler ItemClicked; 71 /// 72 /// The data source 73 /// 74 private MindMappingItemEntity dataSource; 75 /// 76 /// Gets or sets the data source. 77 /// 78 /// The data source. 79 [Description("数据源"), Category("自定义")] 80 public MindMappingItemEntity DataSource 81 { 82 get { return dataSource; } 83 set 84 { 85 dataSource = value; 86 87 ResetSize(); 88 } 89 } 90 /// 91 /// Initializes a new instance of the class. 92 /// 93 public UCMindMapping() 94 { 95 this.SetStyle(ControlStyles.AllPaintingInWmPaint, true); 96 this.SetStyle(ControlStyles.DoubleBuffer, true); 97 this.SetStyle(ControlStyles.ResizeRedraw, true); 98 this.SetStyle(ControlStyles.Selectable, true); 99 this.SetStyle(ControlStyles.SupportsTransparentBackColor, true); 100 this.SetStyle(ControlStyles.UserPaint, true); 101 this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.None; 102 this.Click += UCMindMapping_Click; 103 this.DoubleClick += UCMindMapping_DoubleClick; 104 this.Load += UCMindMapping_Load; 105 } 106 107 /// 108 /// Handles the Load event of the UCMindMapping control. 109 /// 110 /// The source of the event. 111 /// The instance containing the event data. 112 void UCMindMapping_Load(object sender, EventArgs e) 113 { 114 if (this.Parent != null) 115 { 116 //父控件大小改变时重置大小和位置 117 this.Parent.SizeChanged += (a, b) => 118 { 119 ResetSize(); 120 }; 121 } 122 } 123 124 /// 125 /// 双击处理,主要用于检测节点双击展开折叠 126 /// 127 /// The source of the event. 128 /// The instance containing the event data. 129 void UCMindMapping_DoubleClick(object sender, EventArgs e) 130 { 131 var mouseLocation = this.PointToClient(Control.MousePosition); 132 133 bool bln = CheckExpansionDoubleClick(dataSource, mouseLocation); 134 if (bln) 135 { 136 ResetSize(); 137 this.Parent.Refresh(); 138 } 139 } 140 141 /// 142 /// 单击处理,主要用于单击节点事件和,展开关闭圆圈处理 143 /// 144 /// The source of the event. 145 /// The instance containing the event data. 146 void UCMindMapping_Click(object sender, EventArgs e) 147 { 148 var mouseLocation = this.PointToClient(Control.MousePosition); 149 150 bool bln = CheckExpansionClick(dataSource, mouseLocation); 151 if (bln) 152 { 153 ResetSize(); 154 this.Parent.Refresh(); 155 } 156 } 157 158 /// 159 /// 双击检查 160 /// 161 /// The item. 162 /// The mouse location. 163 /// true if XXXX, false otherwise. 164 private bool CheckExpansionDoubleClick(MindMappingItemEntity item, Point mouseLocation) 165 { 166 if (item == null) 167 return false; 168 else 169 { 170 if (item.DrawRectangle.Contains(mouseLocation)) 171 { 172 item.IsExpansion = !item.IsExpansion; 173 return true; 174 } 175 if (item.Childrens != null && item.Childrens.Length > 0) 176 { 177 foreach (var child in item.Childrens) 178 { 179 var bln = CheckExpansionDoubleClick(child, mouseLocation); 180 if (bln) 181 return bln; 182 } 183 } 184 } 185 return false; 186 } 187 188 /// 189 /// 单击检查 190 /// 191 /// The item. 192 /// The mouse location. 193 /// true if XXXX, false otherwise. 194 private bool CheckExpansionClick(MindMappingItemEntity item, Point mouseLocation) 195 { 196 if (item == null) 197 return false; 198 else 199 { 200 if (ItemClicked != null && item.WorkingRectangle.Contains(mouseLocation)) 201 { 202 ItemClicked(item, null); 203 } 204 else if (item.ExpansionRectangle.Contains(mouseLocation)) 205 { 206 item.IsExpansion = !item.IsExpansion; 207 return true; 208 } 209 if (item.Childrens != null && item.Childrens.Length > 0) 210 { 211 foreach (var child in item.Childrens) 212 { 213 var bln = CheckExpansionClick(child, mouseLocation); 214 if (bln) 215 return bln; 216 } 217 } 218 } 219 return false; 220 } 221 222 /// 223 /// 引发 事件。 224 /// 225 /// 包含事件数据的 。 226 protected override void OnPaint(PaintEventArgs e) 227 { 228 try 229 { 230 base.OnPaint(e); 231 if (m_rectWorking == Rectangle.Empty || m_rectWorking == null) 232 return; 233 var g = e.Graphics; 234 g.SetGDIHigh(); 235 236 int intHeight = dataSource.AllChildrensMaxShowHeight; 237 dataSource.WorkingRectangle = new RectangleF(m_rectWorking.Left, m_rectWorking.Top + (m_rectWorking.Height - intHeight) / 2, m_rectWorking.Width, intHeight); 238 239 DrawItem(dataSource, g); 240 } 241 catch (Exception exc) 242 { 243 MessageBox.Show(exc.ToString(), "错误"); 244 } 245 } 246 247 /// 248 /// 画节点 249 /// 250 /// The item. 251 /// The g. 252 private void DrawItem(MindMappingItemEntity item, Graphics g) 253 { 254 //节点 255 var size = g.MeasureString(item.Text, item.Font); 256 item.DrawRectangle = new RectangleF(item.WorkingRectangle.Left + 2, item.WorkingRectangle.Top + (item.WorkingRectangle.Height - size.Height) / 2 + 2, size.Width + 4, size.Height + 4); 257 GraphicsPath drawPath = item.DrawRectangle.CreateRoundedRectanglePath(5); 258 g.FillPath(new SolidBrush(item.BackColor), drawPath); 259 g.DrawString(item.Text, item.Font, new SolidBrush(item.ForeColor), item.DrawRectangle.Location.X + 2, item.DrawRectangle.Location.Y + 2); 260 //子节点 261 if (item.Childrens != null && item.IsExpansion) 262 { 263 for (int i = 0; i < item.Childrens.Length; i++) 264 { 265 var child = item.Childrens[i]; 266 if (i == 0) 267 { 268 child.WorkingRectangle = new RectangleF(item.DrawRectangle.Right + splitWidth, item.WorkingRectangle.Top, item.WorkingRectangle.Width - (item.DrawRectangle.Width + splitWidth), child.AllChildrensMaxShowHeight); 269 } 270 else 271 { 272 child.WorkingRectangle = new RectangleF(item.DrawRectangle.Right + splitWidth, item.Childrens[i - 1].WorkingRectangle.Bottom, item.WorkingRectangle.Width - (item.DrawRectangle.Width + splitWidth), child.AllChildrensMaxShowHeight); 273 } 274 DrawItem(child, g); 275 } 276 } 277 //连线 278 if (item.ParentItem != null) 279 { 280 g.DrawLines(new Pen(new SolidBrush(lineColor), 1), new PointF[] 281 { 282 new PointF(item.ParentItem.DrawRectangle.Right,item.ParentItem.DrawRectangle.Top+item.ParentItem.DrawRectangle.Height/2), 283 new PointF(item.ParentItem.DrawRectangle.Right+12,item.ParentItem.DrawRectangle.Top+item.ParentItem.DrawRectangle.Height/2), 284 //new PointF(item.ParentItem.DrawRectangle.Right+12,item.DrawRectangle.Top+item.DrawRectangle.Height/2), 285 new PointF(item.DrawRectangle.Left-12,item.DrawRectangle.Top+item.DrawRectangle.Height/2), 286 new PointF(item.DrawRectangle.Left,item.DrawRectangle.Top+item.DrawRectangle.Height/2), 287 }); 288 } 289 //展开折叠按钮 290 if (item.Childrens != null && item.Childrens.Length > 0) 291 { 292 RectangleF _rect = new RectangleF(item.DrawRectangle.Right + 1, item.DrawRectangle.Top + (item.DrawRectangle.Height - 10) / 2, 10, 10); 293 item.ExpansionRectangle = _rect; 294 g.FillEllipse(new SolidBrush(this.BackColor), _rect); 295 g.DrawEllipse(new Pen(new SolidBrush(Color.Black)), _rect); 296 g.DrawLine(new Pen(new SolidBrush(lineColor)), _rect.Left + 2, _rect.Y + _rect.Height / 2, _rect.Right - 2, _rect.Y + _rect.Height / 2); 297 if (!item.IsExpansion) 298 { 299 g.DrawLine(new Pen(new SolidBrush(lineColor)), _rect.Left + _rect.Width / 2, _rect.Top + 2, _rect.Left + _rect.Width / 2, _rect.Bottom - 2); 300 } 301 } 302 } 303 304 305 /// 306 /// 重置大小 307 /// 308 private void ResetSize() 309 { 310 if (this.Parent == null) 311 return; 312 try 313 { 314 ControlHelper.FreezeControl(this, true); 315 if (dataSource == null) 316 { 317 m_rectWorking = Rectangle.Empty; 318 this.Size = this.Parent.Size; 319 } 320 else 321 { 322 int intWidth = dataSource.AllChildrensMaxShowWidth; 323 int intHeight = dataSource.AllChildrensMaxShowHeight; 324 this.Width = intWidth + padding * 2; 325 this.Height = intHeight + padding * 2; 326 if (this.Width < this.Parent.Width) 327 this.Width = this.Parent.Width; 328 m_rectWorking = new Rectangle(padding, padding, intWidth, intHeight); 329 if (this.Height > this.Parent.Height) 330 { 331 //this.Location = new Point(0, 0); 332 } 333 else 334 this.Location = new Point(0, (this.Parent.Height - this.Height) / 2); 335 } 336 } 337 finally 338 { 339 ControlHelper.FreezeControl(this, false); 340 } 341 } 342 } 343 }
最后再添加一个父控件,来包裹该控件,用以可以有滚动条的处理
添加一个用户控件UCMindMappingPanel,控件上添加一个上面新增的ucMindMapping,
完整代码
1 // *********************************************************************** 2 // Assembly : HZH_Controls 3 // Created : 2019-09-11 4 // 5 // *********************************************************************** 6 //7 // Copyright by Huang Zhenghui(黄正辉) All, QQ group:568015492 QQ:623128629 Email:[email protected] 8 // 9 // 10 // Blog: https://www.cnblogs.com/bfyx 11 // GitHub:https://github.com/kwwwvagaa/NetWinformControl 12 // gitee:https://gitee.com/kwwwvagaa/net_winform_custom_control.git 13 // 14 // If you use this code, please keep this note. 15 // *********************************************************************** 16 using System; 17 using System.Collections.Generic; 18 using System.ComponentModel; 19 using System.Drawing; 20 using System.Data; 21 using System.Linq; 22 using System.Text; 23 using System.Windows.Forms; 24 25 namespace HZH_Controls.Controls 26 { 27 /// 28 /// Class UCMindMappingPanel. 29 /// Implements the 30 /// 31 /// 32 public partial class UCMindMappingPanel : UserControl 33 { 34 /// 35 /// The data source 36 /// 37 private MindMappingItemEntity dataSource; 38 39 /// 40 /// Gets or sets the data source. 41 /// 42 /// The data source. 43 [Description("数据源"), Category("自定义")] 44 public MindMappingItemEntity DataSource 45 { 46 get { return dataSource; } 47 set 48 { 49 dataSource = value; 50 this.ucMindMapping1.DataSource = value; 51 } 52 } 53 /// 54 /// Gets or sets the data source. 55 /// 56 /// The data source. 57 [Description("数据源"), Category("自定义")] 58 public event EventHandler ItemClicked; 59 60 /// 61 /// The line color 62 /// 63 private Color lineColor = Color.Black; 64 65 /// 66 /// Gets or sets the color of the line. 67 /// 68 /// The color of the line. 69 [Description("线条颜色"), Category("自定义")] 70 public Color LineColor 71 { 72 get { return lineColor; } 73 set 74 { 75 lineColor = value; 76 this.ucMindMapping1.LineColor = value; 77 } 78 } 79 /// 80 /// Initializes a new instance of the class. 81 /// 82 public UCMindMappingPanel() 83 { 84 this.SetStyle(ControlStyles.AllPaintingInWmPaint, true); 85 this.SetStyle(ControlStyles.DoubleBuffer, true); 86 this.SetStyle(ControlStyles.ResizeRedraw, true); 87 this.SetStyle(ControlStyles.Selectable, true); 88 this.SetStyle(ControlStyles.SupportsTransparentBackColor, true); 89 this.SetStyle(ControlStyles.UserPaint, true); 90 InitializeComponent(); 91 ucMindMapping1.ItemClicked += ucMindMapping1_ItemClicked; 92 } 93 94 void ucMindMapping1_ItemClicked(object sender, EventArgs e) 95 { 96 if (ItemClicked != null) 97 { 98 ItemClicked(sender, e); 99 } 100 } 101 } 102 }
1 namespace HZH_Controls.Controls 2 { 3 partial class UCMindMappingPanel 4 { 5 ///6 /// 必需的设计器变量。 7 /// 8 private System.ComponentModel.IContainer components = null; 9 10 /// 11 /// 清理所有正在使用的资源。 12 /// 13 /// 如果应释放托管资源,为 true;否则为 false。 14 protected override void Dispose(bool disposing) 15 { 16 if (disposing && (components != null)) 17 { 18 components.Dispose(); 19 } 20 base.Dispose(disposing); 21 } 22 23 #region 组件设计器生成的代码 24 25 /// 26 /// 设计器支持所需的方法 - 不要 27 /// 使用代码编辑器修改此方法的内容。 28 /// 29 private void InitializeComponent() 30 { 31 this.ucMindMapping1 = new HZH_Controls.Controls.UCMindMapping(); 32 this.SuspendLayout(); 33 // 34 // ucMindMapping1 35 // 36 this.ucMindMapping1.Location = new System.Drawing.Point(0, 0); 37 this.ucMindMapping1.Name = "ucMindMapping1"; 38 this.ucMindMapping1.Size = new System.Drawing.Size(200, 200); 39 this.ucMindMapping1.TabIndex = 0; 40 // 41 // UCMindMappingPanel 42 // 43 this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.None; 44 this.AutoScroll = true; 45 this.BackColor = System.Drawing.Color.White; 46 this.Controls.Add(this.ucMindMapping1); 47 this.Name = "UCMindMappingPanel"; 48 this.Size = new System.Drawing.Size(200, 200); 49 this.ResumeLayout(false); 50 51 } 52 53 #endregion 54 55 private UCMindMapping ucMindMapping1; 56 } 57 }
最后的话
如果你喜欢的话,请到 https://gitee.com/kwwwvagaa/net_winform_custom_control 点个星星吧