当前位置: 移动技术网 > IT编程>开发语言>.net > (六十五)c#Winform自定义控件-思维导图/组织架构图(工业)

(六十五)c#Winform自定义控件-思维导图/组织架构图(工业)

2019年09月11日  | 移动技术网IT编程  | 我要评论

前提

入行已经7,8年了,一直想做一套漂亮点的自定义控件,于是就有了本系列文章。

github:https://github.com/kwwwvagaa/netwinformcontrol

码云:

如果觉得写的还行,请点个 star 支持一下吧

欢迎前来交流探讨: 企鹅群568015492 

麻烦博客下方点个【推荐】,谢谢

nuget

install-package hzh_controls

目录

用处及效果

准备工作

依然是用gdi+画的,不懂的可以先百度一下

开始

添加一个实体类,用以记录数据源节点信息

  1  public class mindmappingitementity
  2     {
  3         /// <summary>
  4         /// gets or sets the identifier.
  5         /// </summary>
  6         /// <value>the identifier.</value>
  7         public string id { get; set; }
  8         private string _text;
  9         /// <summary>
 10         /// gets or sets the text.
 11         /// </summary>
 12         /// <value>the text.</value>
 13         public string text
 14         {
 15             get { return _text; }
 16             set
 17             {
 18                 _text = value;
 19                 resetsize();
 20             }
 21         }
 22         /// <summary>
 23         /// gets or sets the data source.
 24         /// </summary>
 25         /// <value>the data source.</value>
 26         public object datasource { get; set; }
 27         /// <summary>
 28         /// the childrens
 29         /// </summary>
 30         private mindmappingitementity[] _childrens;
 31         /// <summary>
 32         /// gets or sets the childrens.
 33         /// </summary>
 34         /// <value>the childrens.</value>
 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         /// <summary>
 48         /// the back color
 49         /// </summary>
 50         private color backcolor = color.transparent;
 51 
 52         /// <summary>
 53         /// gets or sets the color of the back.
 54         /// </summary>
 55         /// <value>the color of the back.</value>
 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         /// <summary>
 75         /// the fore color
 76         /// </summary>
 77         private color forecolor = color.black;
 78 
 79         /// <summary>
 80         /// gets or sets the color of the fore.
 81         /// </summary>
 82         /// <value>the color of the fore.</value>
 83         public color forecolor
 84         {
 85             get { return forecolor; }
 86             set { forecolor = value; }
 87         }
 88         private bool _isexpansion = false;
 89         /// <summary>
 90         /// gets or sets a value indicating whether the instance is expanded.
 91         /// </summary>
 92         /// <value><c>true</c> if this instance is expansion; otherwise, <c>false</c>.</value>
 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         /// <summary>
113         /// gets the parent item.
114         /// </summary>
115         /// <value>the parent item.</value>
116         public mindmappingitementity parentitem { get; private set; }
117         /// <summary>
118         /// gets all childrens maximum show count.
119         /// </summary>
120         /// <value>all childrens maximum show count.</value>
121         public int allchildrensmaxshowheight { get { return getallchildrensmaxshowheight(); } }
122         /// <summary>
123         /// gets the maximum level.
124         /// </summary>
125         /// <value>the maximum level.</value>
126         public int allchildrensmaxshowwidth { get { return getallchildrensmaxshowwidth(); } }
127 
128         /// <summary>
129         /// gets all childrens maximum show count.
130         /// </summary>
131         /// <returns>system.int32.</returns>
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         /// <summary>
142         /// gets the maximum level.
143         /// </summary>
144         /// <returns>system.int32.</returns>
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         /// <summary>
155         /// gets or sets the working rectangle.
156         /// </summary>
157         /// <value>the working rectangle.</value>
158         internal rectanglef workingrectangle { get; set; }
159         /// <summary>
160         /// gets or sets the draw rectangle.
161         /// </summary>
162         /// <value>the draw rectangle.</value>
163         internal rectanglef drawrectangle { get; set; }
164         /// <summary>
165         /// gets or sets the expansion rectangle.
166         /// </summary>
167         /// <value>the expansion rectangle.</value>
168         internal rectanglef expansionrectangle { get; set; }
169         /// <summary>
170         /// gets the height of the item.
171         /// </summary>
172         /// <value>the height of the item.</value>
173         private int itemheight { private get; private set; }
174         /// <summary>
175         /// gets the width of the item.
176         /// </summary>
177         /// <value>the width of the item.</value>
178         private int itemwidth { private get; private set; }
179         /// <summary>
180         /// resets the size.
181         /// </summary>
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  /// <summary>
 2         /// the line color
 3         /// </summary>
 4         private color linecolor = color.black;
 5 
 6         /// <summary>
 7         /// gets or sets the color of the line.
 8         /// </summary>
 9         /// <value>the color of the line.</value>
10         [description("线条颜色"), category("自定义")]
11         public color linecolor
12         {
13             get { return linecolor; }
14             set
15             {
16                 linecolor = value;
17                 refresh();
18             }
19         }
20         /// <summary>
21         /// the split width
22         /// </summary>
23         private int splitwidth = 50;
24         // private int itemheight = 20;
25         /// <summary>
26         /// the padding
27         /// </summary>
28         private int padding = 20;
29 
30         /// <summary>
31         /// the m rect working
32         /// </summary>
33         rectangle m_rectworking = rectangle.empty;
34         /// <summary>
35         /// occurs when [item clicked].
36         /// </summary>
37         public event eventhandler itemclicked;
38         /// <summary>
39         /// the data source
40         /// </summary>
41         private mindmappingitementity datasource;
42         /// <summary>
43         /// gets or sets the data source.
44         /// </summary>
45         /// <value>the data source.</value>
46         [description("数据源"), category("自定义")]
47         public mindmappingitementity datasource
48         {
49             get { return datasource; }
50             set
51             {
52                 datasource = value;
53 
54                 resetsize();
55             }
56         }

一个辅助函数,用以在大小过数据改变时计算工作区域和位置

 1  /// <summary>
 2         /// 重置大小
 3         /// </summary>
 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  /// <summary>
 2         /// 引发 <see cref="e:system.windows.forms.control.paint" /> 事件。
 3         /// </summary>
 4         /// <param name="e">包含事件数据的 <see cref="t:system.windows.forms.painteventargs" />。</param>
 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 /// <summary>
 2         /// 画节点
 3         /// </summary>
 4         /// <param name="item">the item.</param>
 5         /// <param name="g">the g.</param>
 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  /// <summary>
 2         /// 双击处理,主要用于检测节点双击展开折叠
 3         /// </summary>
 4         /// <param name="sender">the source of the event.</param>
 5         /// <param name="e">the <see cref="eventargs"/> instance containing the event data.</param>
 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         /// <summary>
19         /// 单击处理,主要用于单击节点事件和,展开关闭圆圈处理
20         /// </summary>
21         /// <param name="sender">the source of the event.</param>
22         /// <param name="e">the <see cref="eventargs"/> instance containing the event data.</param>
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   /// <summary>
 2         /// 双击检查
 3         /// </summary>
 4         /// <param name="item">the item.</param>
 5         /// <param name="mouselocation">the mouse location.</param>
 6         /// <returns><c>true</c> if xxxx, <c>false</c> otherwise.</returns>
 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         /// <summary>
32         /// 单击检查
33         /// </summary>
34         /// <param name="item">the item.</param>
35         /// <param name="mouselocation">the mouse location.</param>
36         /// <returns><c>true</c> if xxxx, <c>false</c> otherwise.</returns>
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 // <copyright file="ucmindmapping.cs">
  7 //     copyright by huang zhenghui(黄正辉) all, qq group:568015492 qq:623128629 email:623128629@qq.com
  8 // </copyright>
  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     /// <summary>
 28     /// class ucmindmapping.
 29     /// implements the <see cref="system.windows.forms.usercontrol" />
 30     /// </summary>
 31     /// <seealso cref="system.windows.forms.usercontrol" />
 32     internal class ucmindmapping : usercontrol
 33     {
 34         /// <summary>
 35         /// the line color
 36         /// </summary>
 37         private color linecolor = color.black;
 38 
 39         /// <summary>
 40         /// gets or sets the color of the line.
 41         /// </summary>
 42         /// <value>the color of the line.</value>
 43         [description("线条颜色"), category("自定义")]
 44         public color linecolor
 45         {
 46             get { return linecolor; }
 47             set
 48             {
 49                 linecolor = value;
 50                 refresh();
 51             }
 52         }
 53         /// <summary>
 54         /// the split width
 55         /// </summary>
 56         private int splitwidth = 50;
 57         // private int itemheight = 20;
 58         /// <summary>
 59         /// the padding
 60         /// </summary>
 61         private int padding = 20;
 62 
 63         /// <summary>
 64         /// the m rect working
 65         /// </summary>
 66         rectangle m_rectworking = rectangle.empty;
 67         /// <summary>
 68         /// occurs when [item clicked].
 69         /// </summary>
 70         public event eventhandler itemclicked;
 71         /// <summary>
 72         /// the data source
 73         /// </summary>
 74         private mindmappingitementity datasource;
 75         /// <summary>
 76         /// gets or sets the data source.
 77         /// </summary>
 78         /// <value>the data source.</value>
 79         [description("数据源"), category("自定义")]
 80         public mindmappingitementity datasource
 81         {
 82             get { return datasource; }
 83             set
 84             {
 85                 datasource = value;
 86 
 87                 resetsize();
 88             }
 89         }
 90         /// <summary>
 91         /// initializes a new instance of the <see cref="ucmindmapping"/> class.
 92         /// </summary>
 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         /// <summary>
108         /// handles the load event of the ucmindmapping control.
109         /// </summary>
110         /// <param name="sender">the source of the event.</param>
111         /// <param name="e">the <see cref="eventargs"/> instance containing the event data.</param>
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         /// <summary>
125         /// 双击处理,主要用于检测节点双击展开折叠
126         /// </summary>
127         /// <param name="sender">the source of the event.</param>
128         /// <param name="e">the <see cref="eventargs"/> instance containing the event data.</param>
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         /// <summary>
142         /// 单击处理,主要用于单击节点事件和,展开关闭圆圈处理
143         /// </summary>
144         /// <param name="sender">the source of the event.</param>
145         /// <param name="e">the <see cref="eventargs"/> instance containing the event data.</param>
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         /// <summary>
159         /// 双击检查
160         /// </summary>
161         /// <param name="item">the item.</param>
162         /// <param name="mouselocation">the mouse location.</param>
163         /// <returns><c>true</c> if xxxx, <c>false</c> otherwise.</returns>
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         /// <summary>
189         /// 单击检查
190         /// </summary>
191         /// <param name="item">the item.</param>
192         /// <param name="mouselocation">the mouse location.</param>
193         /// <returns><c>true</c> if xxxx, <c>false</c> otherwise.</returns>
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         /// <summary>
223         /// 引发 <see cref="e:system.windows.forms.control.paint" /> 事件。
224         /// </summary>
225         /// <param name="e">包含事件数据的 <see cref="t:system.windows.forms.painteventargs" />。</param>
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         /// <summary>
248         /// 画节点
249         /// </summary>
250         /// <param name="item">the item.</param>
251         /// <param name="g">the g.</param>
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         /// <summary>
306         /// 重置大小
307         /// </summary>
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 // <copyright file="ucmindmappingpanel.cs">
  7 //     copyright by huang zhenghui(黄正辉) all, qq group:568015492 qq:623128629 email:623128629@qq.com
  8 // </copyright>
  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     /// <summary>
 28     /// class ucmindmappingpanel.
 29     /// implements the <see cref="system.windows.forms.usercontrol" />
 30     /// </summary>
 31     /// <seealso cref="system.windows.forms.usercontrol" />
 32     public partial class ucmindmappingpanel : usercontrol
 33     {
 34         /// <summary>
 35         /// the data source
 36         /// </summary>
 37         private mindmappingitementity datasource;
 38 
 39         /// <summary>
 40         /// gets or sets the data source.
 41         /// </summary>
 42         /// <value>the data source.</value>
 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         /// <summary>
 54         /// gets or sets the data source.
 55         /// </summary>
 56         /// <value>the data source.</value>
 57         [description("数据源"), category("自定义")]
 58         public event eventhandler itemclicked;
 59 
 60         /// <summary>
 61         /// the line color
 62         /// </summary>
 63         private color linecolor = color.black;
 64 
 65         /// <summary>
 66         /// gets or sets the color of the line.
 67         /// </summary>
 68         /// <value>the color of the line.</value>
 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         /// <summary>
 80         /// initializes a new instance of the <see cref="ucmindmappingpanel"/> class.
 81         /// </summary>
 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         /// <summary> 
 6         /// 必需的设计器变量。
 7         /// </summary>
 8         private system.componentmodel.icontainer components = null;
 9 
10         /// <summary> 
11         /// 清理所有正在使用的资源。
12         /// </summary>
13         /// <param name="disposing">如果应释放托管资源,为 true;否则为 false。</param>
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         /// <summary> 
26         /// 设计器支持所需的方法 - 不要
27         /// 使用代码编辑器修改此方法的内容。
28         /// </summary>
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 }

最后的话

如果你喜欢的话,请到  点个星星吧

如对本文有疑问, 点击进行留言回复!!

相关文章:

验证码:
移动技术网