(六十五)c#Winform自定义控件-思维导图/组织架构图(工业)
前提
入行已经7,8年了,一直想做一套漂亮点的自定义控件,于是就有了本系列文章。
GitHub:https://github.com/kwwwvagaa/NetWinformControl
码云:https://gitee.com/kwwwvagaa/net_winform_custom_control.git
如果觉得写的还行,请点个 star 支持一下吧
欢迎前来交流探讨: 企鹅群568015492 企鹅群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.WorkingRectang