前提

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

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

码云:

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

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

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

nuget

install-package hzh_controls

目录

用处及效果

准备工作

依然使用gdi+画图,不懂的先百度了解下

开始

添加一些枚举

 1  public enum funelchartalignment
 2     {
 3         /// <summary>
 4         /// the left
 5         /// </summary>
 6         left,
 7         /// <summary>
 8         /// the center
 9         /// </summary>
10         center,
11         /// <summary>
12         /// the right
13         /// </summary>
14         right
15     }
16 
17  public enum funelchartdirection
18     {
19         /// <summary>
20         /// up
21         /// </summary>
22         up,
23         /// <summary>
24         /// down
25         /// </summary>
26         down
27     }

添加一个项实体

 1   public class funelchartitem
 2     {
 3         /// <summary>
 4         /// gets or sets the text.
 5         /// </summary>
 6         /// <value>the text.</value>
 7         public string text { get; set; }
 8         /// <summary>
 9         /// gets or sets the value.
10         /// </summary>
11         /// <value>the value.</value>
12         public float value { get; set; }
13         /// <summary>
14         /// gets or sets the color of the value.
15         /// </summary>
16         /// <value>the color of the value.</value>
17         public system.drawing.color? valuecolor { get; set; }
18         /// <summary>
19         /// gets or sets the color of the text fore.
20         /// </summary>
21         /// <value>the color of the text fore.</value>
22         public system.drawing.color? textforecolor { get; set; }
23     }

添加一个类ucfunnelchart ,继承usercontrol

添加一些控制属性

  1 /// <summary>
  2         /// the title
  3         /// </summary>
  4         private string title;
  5         /// <summary>
  6         /// gets or sets the title.
  7         /// </summary>
  8         /// <value>the title.</value>
  9         [browsable(true)]
 10         [category("自定义")]
 11         [description("获取或设置标题")]
 12         public string title
 13         {
 14             get { return title; }
 15             set
 16             {
 17                 title = value;
 18                 resettitlesize();
 19                 invalidate();
 20             }
 21         }
 22 
 23         /// <summary>
 24         /// the title font
 25         /// </summary>
 26         private font titlefont = new font("微软雅黑", 12);
 27         /// <summary>
 28         /// gets or sets the title font.
 29         /// </summary>
 30         /// <value>the title font.</value>
 31         [browsable(true)]
 32         [category("自定义")]
 33         [description("获取或设置标题字体")]
 34         public font titlefont
 35         {
 36             get { return titlefont; }
 37             set
 38             {
 39                 titlefont = value;
 40                 resettitlesize();
 41                 invalidate();
 42             }
 43         }
 44 
 45         /// <summary>
 46         /// the title fore color
 47         /// </summary>
 48         private color titleforecolor = color.black;
 49         /// <summary>
 50         /// gets or sets the color of the title fore.
 51         /// </summary>
 52         /// <value>the color of the title fore.</value>
 53         [browsable(true)]
 54         [category("自定义")]
 55         [description("获取或设置标题文字颜色")]
 56         public color titleforecolor
 57         {
 58             get { return titleforecolor; }
 59             set
 60             {
 61                 titleforecolor = value;
 62                 invalidate();
 63             }
 64         }
 65         /// <summary>
 66         /// the items
 67         /// </summary>
 68         private funelchartitem[] items;
 69         /// <summary>
 70         /// gets or sets the items.
 71         /// </summary>
 72         /// <value>the items.</value>
 73         [browsable(true)]
 74         [category("自定义")]
 75         [description("获取或设置项目")]
 76         public funelchartitem[] items
 77         {
 78             get { return items; }
 79             set
 80             {
 81                 items = value;
 82                 invalidate();
 83             }
 84         }
 85 
 86         /// <summary>
 87         /// the direction
 88         /// </summary>
 89         private funelchartdirection direction = funelchartdirection.up;
 90         /// <summary>
 91         /// gets or sets the direction.
 92         /// </summary>
 93         /// <value>the direction.</value>
 94         [browsable(true)]
 95         [category("自定义")]
 96         [description("获取或设置方向")]
 97         public funelchartdirection direction
 98         {
 99             get { return direction; }
100             set
101             {
102                 direction = value;
103                 invalidate();
104             }
105         }
106 
107         /// <summary>
108         /// the alignment
109         /// </summary>
110         private funelchartalignment alignment = funelchartalignment.center;
111         /// <summary>
112         /// gets or sets the alignment.
113         /// </summary>
114         /// <value>the alignment.</value>
115         [browsable(true)]
116         [category("自定义")]
117         [description("获取或设置对齐方式")]
118         public funelchartalignment alignment
119         {
120             get { return alignment; }
121             set
122             {
123                 alignment = value;
124                 invalidate();
125             }
126         }
127 
128         /// <summary>
129         /// the item text align
130         /// </summary>
131         private funelchartalignment itemtextalign = funelchartalignment.center;
132         /// <summary>
133         /// gets or sets the item text align.
134         /// </summary>
135         /// <value>the item text align.</value>
136         [browsable(true)]
137         [category("自定义")]
138         [description("获取或设置文字位置")]
139         public funelchartalignment itemtextalign
140         {
141             get { return itemtextalign; }
142             set
143             {
144                 itemtextalign = value;
145                 resetworkingrect();
146                 invalidate();
147             }
148         }
149         /// <summary>
150         /// the show value
151         /// </summary>
152         private bool showvalue = false;
153         /// <summary>
154         /// gets or sets a value indicating whether [show value].
155         /// </summary>
156         /// <value><c>true</c> if [show value]; otherwise, <c>false</c>.</value>
157         [browsable(true)]
158         [category("自定义")]
159         [description("获取或设置是否显示值")]
160         public bool showvalue
161         {
162             get { return showvalue; }
163             set
164             {
165                 showvalue = value;
166                 invalidate();
167             }
168         }
169 
170 
171         /// <summary>
172         /// the value format
173         /// </summary>
174         private string valueformat = "0.##";
175         /// <summary>
176         /// gets or sets the value format.
177         /// </summary>
178         /// <value>the value format.</value>
179         [browsable(true)]
180         [category("自定义")]
181         [description("获取或设置值格式化")]
182         public string valueformat
183         {
184             get { return valueformat; }
185             set
186             {
187                 valueformat = value;
188                 invalidate();
189             }
190         }
191 
192         /// <summary>
193         /// the m rect working
194         /// </summary>
195         rectanglef m_rectworking;
196         /// <summary>
197         /// the m title size
198         /// </summary>
199         sizef m_titlesize = sizef.empty;
200         /// <summary>
201         /// the int split width
202         /// </summary>
203         int intsplitwidth = 1;

构造函数初始化

 1  public ucfunnelchart()
 2         {
 3             this.setstyle(controlstyles.allpaintinginwmpaint, true);
 4             this.setstyle(controlstyles.doublebuffer, true);
 5             this.setstyle(controlstyles.resizeredraw, true);
 6             this.setstyle(controlstyles.selectable, true);
 7             this.setstyle(controlstyles.supportstransparentbackcolor, true);
 8             this.setstyle(controlstyles.userpaint, true);
 9             this.fontchanged += ucfunnelchart_fontchanged;
10             font = new font("微软雅黑", 8);
11 
12             this.autoscalemode = system.windows.forms.autoscalemode.none;
13             this.sizechanged += ucfunnelchart_sizechanged;
14             size = new system.drawing.size(150, 150);
15             items = new funelchartitem[0];
16             if (controlhelper.isdesignmode())
17             {
18                 items = new funelchartitem[5];
19                 for (int i = 0; i < 5; i++)
20                 {
21                     items[i] = new funelchartitem()
22                     {
23                         text = "item" + i,
24                         value = 10 * (i + 1)
25                     };
26                 }
27             }
28         }

当大小及状态改变时 重新计算工作区域

 1   void ucfunnelchart_fontchanged(object sender, eventargs e)
 2         {
 3             resetworkingrect();
 4         }
 5 
 6         /// <summary>
 7         /// handles the sizechanged event of the ucfunnelchart control.
 8         /// </summary>
 9         /// <param name="sender">the source of the event.</param>
10         /// <param name="e">the <see cref="eventargs"/> instance containing the event data.</param>
11         void ucfunnelchart_sizechanged(object sender, eventargs e)
12         {
13             resetworkingrect();
14         }
15 
16         /// <summary>
17         /// resets the working rect.
18         /// </summary>
19         private void resetworkingrect()
20         {
21             if (itemtextalign == funelchartalignment.center)
22             {
23                 m_rectworking = new rectanglef(0, m_titlesize.height == 0 ? 0 : (m_titlesize.height + 10), this.width, this.height - (m_titlesize.height == 0 ? 0 : (m_titlesize.height + 10)));
24             }
25             else if (itemtextalign == funelchartalignment.left)
26             {
27                 float fltmax = 0;
28                 if (items != null && items.length > 0)
29                 {
30                     using (graphics g = this.creategraphics())
31                     {
32                         fltmax = items.max(p => g.measurestring(p.text, font).width);
33                     }
34                 }
35                 m_rectworking = new rectanglef(fltmax, m_titlesize.height == 0 ? 0 : (m_titlesize.height + 10), this.width - fltmax, this.height - (m_titlesize.height == 0 ? 0 : (m_titlesize.height + 10)));
36             }
37             else
38             {
39                 float fltmax = 0;
40                 if (items != null && items.length > 0)
41                 {
42                     using (graphics g = this.creategraphics())
43                     {
44                         fltmax = items.max(p => g.measurestring(p.text, font).width);
45                     }
46                 }
47                 m_rectworking = new rectanglef(0, m_titlesize.height == 0 ? 0 : (m_titlesize.height + 10), this.width - fltmax, this.height - (m_titlesize.height == 0 ? 0 : (m_titlesize.height + 10)));
48             }
49         }
50 
51         /// <summary>
52         /// resets the size of the title.
53         /// </summary>
54         private void resettitlesize()
55         {
56             if (string.isnullorempty(title))
57             {
58                 m_titlesize = sizef.empty;
59             }
60             else
61             {
62                 using (graphics g = this.creategraphics())
63                 {
64                     m_titlesize = g.measurestring(title, titlefont);
65                     m_titlesize.height += 20;
66                 }
67             }
68             resetworkingrect();
69         }

重绘

  1 protected override void onpaint(painteventargs e)
2         {
3             base.onpaint(e);
4             var g = e.graphics;
5             g.setgdihigh();
6 
7             if (!string.isnullorempty(title))
8             {
9                 g.drawstring(title, titlefont, new solidbrush(titleforecolor), new rectanglef(0, 0, this.width, m_titlesize.height), new stringformat() { alignment = stringalignment.center, linealignment = stringalignment.center });
10             }
11 
12             if (items == null || items.length <= 0)
13             {
14                 g.drawstring("没有数据", font, new solidbrush(color.black), this.m_rectworking, new stringformat() { alignment = stringalignment.center, linealignment = stringalignment.center });
15                 return;
16             }
17 
18             list<funelchartitem> lstitems;
19             if (direction == funelchartdirection.up)
20             {
21                 lstitems = items.orderby(p => p.value).tolist();
22             }
23             else
24             {
25                 lstitems = items.orderbydescending(p => p.value).tolist();
26             }
27 
28             list<rectanglef> lstrects = new list<rectanglef>();
29             list<graphicspath> lstpaths = new list<graphicspath>();
30             float maxvalue = lstitems.max(p => p.value);
31             float dblsplitheight = m_rectworking.height / lstitems.count;
32             for (int i = 0; i < lstitems.count; i++)
33             {
34                 funelchartitem item = lstitems[i];
35                 if (item.valuecolor == null || item.valuecolor == color.empty || item.valuecolor == color.transparent)
36                     item.valuecolor = controlhelper.colors[i];
37 
38                 switch (alignment)
39                 {
40                     case funelchartalignment.left:
41                         lstrects.add(new rectanglef(m_rectworking.left, m_rectworking.top + dblsplitheight * i, item.value / maxvalue * m_rectworking.width, dblsplitheight));
42                         break;
43                     case funelchartalignment.center:
44                         lstrects.add(new rectanglef(m_rectworking.left + (m_rectworking.width - (item.value / maxvalue * m_rectworking.width)) / 2, m_rectworking.top + dblsplitheight * i, item.value / maxvalue * m_rectworking.width, dblsplitheight));
45                         break;
46                     case funelchartalignment.right:
47                         lstrects.add(new rectanglef(m_rectworking.right - (item.value / maxvalue * m_rectworking.width), m_rectworking.top + dblsplitheight * i, item.value / maxvalue * m_rectworking.width, dblsplitheight));
48                         break;
49                 }
50             }
51 
52             for (int i = 0; i < lstrects.count; i++)
53             {
54                 var rect = lstrects[i];
55                 graphicspath path = new graphicspath();
56                 list<pointf> lstpoints = new list<pointf>();
57                 if (direction == funelchartdirection.up)
58                 {
59                     switch (alignment)
60                     {
61                         case funelchartalignment.left:
62                             lstpoints.add(new pointf(rect.left, rect.top));
63                             if (i != 0)
64                             {
65                                 lstpoints.add(new pointf(lstrects[i - 1].right, rect.top));
66                             }
67                             break;
68                         case funelchartalignment.center:
69                             if (i == 0)
70                             {
71                                 lstpoints.add(new pointf(rect.left + rect.width / 2, rect.top));
72                             }
73                             else
74                             {
75                                 lstpoints.add(new pointf(lstrects[i - 1].left, rect.top));
76                                 lstpoints.add(new pointf(lstrects[i - 1].right, rect.top));
77                             }
78                             break;
79                         case funelchartalignment.right:
80                             if (i == 0)
81                             {
82                                 lstpoints.add(new pointf(rect.right, rect.top));
83                             }
84                             else
85                             {
86                                 lstpoints.add(new pointf(rect.right - lstrects[i - 1].width, rect.top));
87                                 lstpoints.add(new pointf(rect.right, rect.top));
88                             }
89                             break;
90                     }
91                     lstpoints.add(new pointf(rect.right, rect.bottom - intsplitwidth));
92                     lstpoints.add(new pointf(rect.left, rect.bottom - intsplitwidth));
93                 }
94                 else
95                 {
96                     lstpoints.add(new pointf(rect.left, rect.top + intsplitwidth));
97                     lstpoints.add(new pointf(rect.right, rect.top + intsplitwidth));
98                     switch (alignment)
99                     {
100                         case funelchartalignment.left:
101                             if (i == lstrects.count - 1)
102                             {
103                                 lstpoints.add(new pointf(rect.left, rect.bottom));
104                             }
105                             else
106                             {
107                                 lstpoints.add(new pointf(lstrects[i + 1].right, rect.bottom));
108                                 lstpoints.add(new pointf(rect.left, rect.bottom));
109                             }
110                             break;
111                         case funelchartalignment.center:
112                             if (i == lstrects.count - 1)
113                             {
114                                 lstpoints.add(new pointf(rect.left + rect.width / 2, rect.bottom));
115                             }
116                             else
117                             {
118                                 lstpoints.add(new pointf(lstrects[i + 1].right, rect.bottom));
119                                 lstpoints.add(new pointf(lstrects[i + 1].left, rect.bottom));
120                             }
121                             break;
122                         case funelchartalignment.right:
123                             if (i == lstrects.count - 1)
124                             {
125                                 lstpoints.add(new pointf(rect.right, rect.bottom));
126                             }
127                             else
128                             {
129                                 lstpoints.add(new pointf(rect.right, rect.bottom));
130                                 lstpoints.add(new pointf(lstrects[i + 1].left, rect.bottom));
131                             }
132                             break;
133                     }
134                 }
135                 path.addlines(lstpoints.toarray());
136                 path.closeallfigures();
137                 // g.drawpath(new pen(new solidbrush(lstitems[i].valuecolor.value)), path);
138                 g.fillpath(new solidbrush(lstitems[i].valuecolor.value), path);
139 
140                 //写字
141                 if (itemtextalign == funelchartalignment.center)
142                 {
143                     g.drawstring(lstitems[i].text + (showvalue ? lstitems[i].value.tostring("\n" + valueformat) : ""), font, new solidbrush((lstitems[i].textforecolor == null || lstitems[i].textforecolor == color.empty || lstitems[i].textforecolor == color.transparent) ? color.white : lstitems[i].textforecolor.value), rect, new stringformat() { alignment = stringalignment.center, linealignment = stringalignment.center });
144                 }
145                 else if (itemtextalign == funelchartalignment.left)
146                 {
147                     g.drawstring(lstitems[i].text + (showvalue ? lstitems[i].value.tostring("\n" + valueformat) : ""), font, new solidbrush((lstitems[i].textforecolor == null || lstitems[i].textforecolor == color.empty || lstitems[i].textforecolor == color.transparent) ? lstitems[i].valuecolor.value : lstitems[i].textforecolor.value), new rectanglef(0, rect.top, rect.left, rect.height), new stringformat() { alignment = stringalignment.far, linealignment = stringalignment.center });
148                     g.drawline(new pen(new solidbrush((lstitems[i].textforecolor == null || lstitems[i].textforecolor == color.empty || lstitems[i].textforecolor == color.transparent) ? lstitems[i].valuecolor.value : lstitems[i].textforecolor.value)), rect.left, rect.top + rect.height / 2, rect.left + rect.width / 2, rect.top + rect.height / 2);
149                 }
150                 else
151                 {
152                     g.drawstring(lstitems[i].text + (showvalue ? lstitems[i].value.tostring("\n" + valueformat) : ""), font, new solidbrush((lstitems[i].textforecolor == null || lstitems[i].textforecolor == color.empty || lstitems[i].textforecolor == color.transparent) ? lstitems[i].valuecolor.value : lstitems[i].textforecolor.value), new rectanglef(rect.right, rect.top, this.width - rect.right, rect.height), new stringformat() { alignment = stringalignment.near, linealignment = stringalignment.center });
153                     g.drawline(new pen(new solidbrush((lstitems[i].textforecolor == null || lstitems[i].textforecolor == color.empty || lstitems[i].textforecolor == color.transparent) ? lstitems[i].valuecolor.value : lstitems[i].textforecolor.value)), rect.left + rect.width / 2, rect.top + rect.height / 2, rect.right, rect.top + rect.height / 2);
154                 }
155             }
156         }

完整代码

  1 // ***********************************************************************
2 // assembly         : hzh_controls
3 // created          : 2019-09-26
4 //
5 // ***********************************************************************
6 // <copyright file="ucfunnelchart.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 ucfunnelchart.
29     /// implements the <see cref="system.windows.forms.usercontrol" />
30     /// </summary>
31     /// <seealso cref="system.windows.forms.usercontrol" />
32     public class ucfunnelchart : usercontrol
33     {
34         /// <summary>
35         /// the title
36         /// </summary>
37         private string title;
38         /// <summary>
39         /// gets or sets the title.
40         /// </summary>
41         /// <value>the title.</value>
42         [browsable(true)]
43         [category("自定义")]
44         [description("获取或设置标题")]
45         public string title
46         {
47             get { return title; }
48             set
49             {
50                 title = value;
51                 resettitlesize();
52                 invalidate();
53             }
54         }
55 
56         /// <summary>
57         /// the title font
58         /// </summary>
59         private font titlefont = new font("微软雅黑", 12);
60         /// <summary>
61         /// gets or sets the title font.
62         /// </summary>
63         /// <value>the title font.</value>
64         [browsable(true)]
65         [category("自定义")]
66         [description("获取或设置标题字体")]
67         public font titlefont
68         {
69             get { return titlefont; }
70             set
71             {
72                 titlefont = value;
73                 resettitlesize();
74                 invalidate();
75             }
76         }
77 
78         /// <summary>
79         /// the title fore color
80         /// </summary>
81         private color titleforecolor = color.black;
82         /// <summary>
83         /// gets or sets the color of the title fore.
84         /// </summary>
85         /// <value>the color of the title fore.</value>
86         [browsable(true)]
87         [category("自定义")]
88         [description("获取或设置标题文字颜色")]
89         public color titleforecolor
90         {
91             get { return titleforecolor; }
92             set
93             {
94                 titleforecolor = value;
95                 invalidate();
96             }
97         }
98         /// <summary>
99         /// the items
100         /// </summary>
101         private funelchartitem[] items;
102         /// <summary>
103         /// gets or sets the items.
104         /// </summary>
105         /// <value>the items.</value>
106         [browsable(true)]
107         [category("自定义")]
108         [description("获取或设置项目")]
109         public funelchartitem[] items
110         {
111             get { return items; }
112             set
113             {
114                 items = value;
115                 invalidate();
116             }
117         }
118 
119         /// <summary>
120         /// the direction
121         /// </summary>
122         private funelchartdirection direction = funelchartdirection.up;
123         /// <summary>
124         /// gets or sets the direction.
125         /// </summary>
126         /// <value>the direction.</value>
127         [browsable(true)]
128         [category("自定义")]
129         [description("获取或设置方向")]
130         public funelchartdirection direction
131         {
132             get { return direction; }
133             set
134             {
135                 direction = value;
136                 invalidate();
137             }
138         }
139 
140         /// <summary>
141         /// the alignment
142         /// </summary>
143         private funelchartalignment alignment = funelchartalignment.center;
144         /// <summary>
145         /// gets or sets the alignment.
146         /// </summary>
147         /// <value>the alignment.</value>
148         [browsable(true)]
149         [category("自定义")]
150         [description("获取或设置对齐方式")]
151         public funelchartalignment alignment
152         {
153             get { return alignment; }
154             set
155             {
156                 alignment = value;
157                 invalidate();
158             }
159         }
160 
161         /// <summary>
162         /// the item text align
163         /// </summary>
164         private funelchartalignment itemtextalign = funelchartalignment.center;
165         /// <summary>
166         /// gets or sets the item text align.
167         /// </summary>
168         /// <value>the item text align.</value>
169         [browsable(true)]
170         [category("自定义")]
171         [description("获取或设置文字位置")]
172         public funelchartalignment itemtextalign
173         {
174             get { return itemtextalign; }
175             set
176             {
177                 itemtextalign = value;
178                 resetworkingrect();
179                 invalidate();
180             }
181         }
182         /// <summary>
183         /// the show value
184         /// </summary>
185         private bool showvalue = false;
186         /// <summary>
187         /// gets or sets a value indicating whether [show value].
188         /// </summary>
189         /// <value><c>true</c> if [show value]; otherwise, <c>false</c>.</value>
190         [browsable(true)]
191         [category("自定义")]
192         [description("获取或设置是否显示值")]
193         public bool showvalue
194         {
195             get { return showvalue; }
196             set
197             {
198                 showvalue = value;
199                 invalidate();
200             }
201         }
202 
203 
204         /// <summary>
205         /// the value format
206         /// </summary>
207         private string valueformat = "0.##";
208         /// <summary>
209         /// gets or sets the value format.
210         /// </summary>
211         /// <value>the value format.</value>
212         [browsable(true)]
213         [category("自定义")]
214         [description("获取或设置值格式化")]
215         public string valueformat
216         {
217             get { return valueformat; }
218             set
219             {
220                 valueformat = value;
221                 invalidate();
222             }
223         }
224 
225         /// <summary>
226         /// the m rect working
227         /// </summary>
228         rectanglef m_rectworking;
229         /// <summary>
230         /// the m title size
231         /// </summary>
232         sizef m_titlesize = sizef.empty;
233         /// <summary>
234         /// the int split width
235         /// </summary>
236         int intsplitwidth = 1;
237 
238         /// <summary>
239         /// initializes a new instance of the <see cref="ucfunnelchart"/> class.
240         /// </summary>
241         public ucfunnelchart()
242         {
243             this.setstyle(controlstyles.allpaintinginwmpaint, true);
244             this.setstyle(controlstyles.doublebuffer, true);
245             this.setstyle(controlstyles.resizeredraw, true);
246             this.setstyle(controlstyles.selectable, true);
247             this.setstyle(controlstyles.supportstransparentbackcolor, true);
248             this.setstyle(controlstyles.userpaint, true);
249             this.fontchanged += ucfunnelchart_fontchanged;
250             font = new font("微软雅黑", 8);
251 
252             this.autoscalemode = system.windows.forms.autoscalemode.none;
253             this.sizechanged += ucfunnelchart_sizechanged;
254             size = new system.drawing.size(150, 150);
255             items = new funelchartitem[0];
256             if (controlhelper.isdesignmode())
257             {
258                 items = new funelchartitem[5];
259                 for (int i = 0; i < 5; i++)
260                 {
261                     items[i] = new funelchartitem()
262                     {
263                         text = "item" + i,
264                         value = 10 * (i + 1)
265                     };
266                 }
267             }
268         }
269 
270         /// <summary>
271         /// handles the fontchanged event of the ucfunnelchart control.
272         /// </summary>
273         /// <param name="sender">the source of the event.</param>
274         /// <param name="e">the <see cref="eventargs"/> instance containing the event data.</param>
275         void ucfunnelchart_fontchanged(object sender, eventargs e)
276         {
277             resetworkingrect();
278         }
279 
280         /// <summary>
281         /// handles the sizechanged event of the ucfunnelchart control.
282         /// </summary>
283         /// <param name="sender">the source of the event.</param>
284         /// <param name="e">the <see cref="eventargs"/> instance containing the event data.</param>
285         void ucfunnelchart_sizechanged(object sender, eventargs e)
286         {
287             resetworkingrect();
288         }
289 
290         /// <summary>
291         /// resets the working rect.
292         /// </summary>
293         private void resetworkingrect()
294         {
295             if (itemtextalign == funelchartalignment.center)
296             {
297                 m_rectworking = new rectanglef(0, m_titlesize.height == 0 ? 0 : (m_titlesize.height + 10), this.width, this.height - (m_titlesize.height == 0 ? 0 : (m_titlesize.height + 10)));
298             }
299             else if (itemtextalign == funelchartalignment.left)
300             {
301                 float fltmax = 0;
302                 if (items != null && items.length > 0)
303                 {
304                     using (graphics g = this.creategraphics())
305                     {
306                         fltmax = items.max(p => g.measurestring(p.text, font).width);
307                     }
308                 }
309                 m_rectworking = new rectanglef(fltmax, m_titlesize.height == 0 ? 0 : (m_titlesize.height + 10), this.width - fltmax, this.height - (m_titlesize.height == 0 ? 0 : (m_titlesize.height + 10)));
310             }
311             else
312             {
313                 float fltmax = 0;
314                 if (items != null && items.length > 0)
315                 {
316                     using (graphics g = this.creategraphics())
317                     {
318                         fltmax = items.max(p => g.measurestring(p.text, font).width);
319                     }
320                 }
321                 m_rectworking = new rectanglef(0, m_titlesize.height == 0 ? 0 : (m_titlesize.height + 10), this.width - fltmax, this.height - (m_titlesize.height == 0 ? 0 : (m_titlesize.height + 10)));
322             }
323         }
324 
325         /// <summary>
326         /// resets the size of the title.
327         /// </summary>
328         private void resettitlesize()
329         {
330             if (string.isnullorempty(title))
331             {
332                 m_titlesize = sizef.empty;
333             }
334             else
335             {
336                 using (graphics g = this.creategraphics())
337                 {
338                     m_titlesize = g.measurestring(title, titlefont);
339                     m_titlesize.height += 20;
340                 }
341             }
342             resetworkingrect();
343         }
344 
345         /// <summary>
346         /// 引发 <see cref="e:system.windows.forms.control.paint" /> 事件。
347         /// </summary>
348         /// <param name="e">包含事件数据的 <see cref="t:system.windows.forms.painteventargs" />。</param>
349         protected override void onpaint(painteventargs e)
350         {
351             base.onpaint(e);
352             var g = e.graphics;
353             g.setgdihigh();
354 
355             if (!string.isnullorempty(title))
356             {
357                 g.drawstring(title, titlefont, new solidbrush(titleforecolor), new rectanglef(0, 0, this.width, m_titlesize.height), new stringformat() { alignment = stringalignment.center, linealignment = stringalignment.center });
358             }
359 
360             if (items == null || items.length <= 0)
361             {
362                 g.drawstring("没有数据", font, new solidbrush(color.black), this.m_rectworking, new stringformat() { alignment = stringalignment.center, linealignment = stringalignment.center });
363                 return;
364             }
365 
366             list<funelchartitem> lstitems;
367             if (direction == funelchartdirection.up)
368             {
369                 lstitems = items.orderby(p => p.value).tolist();
370             }
371             else
372             {
373                 lstitems = items.orderbydescending(p => p.value).tolist();
374             }
375 
376             list<rectanglef> lstrects = new list<rectanglef>();
377             list<graphicspath> lstpaths = new list<graphicspath>();
378             float maxvalue = lstitems.max(p => p.value);
379             float dblsplitheight = m_rectworking.height / lstitems.count;
380             for (int i = 0; i < lstitems.count; i++)
381             {
382                 funelchartitem item = lstitems[i];
383                 if (item.valuecolor == null || item.valuecolor == color.empty || item.valuecolor == color.transparent)
384                     item.valuecolor = controlhelper.colors[i];
385 
386                 switch (alignment)
387                 {
388                     case funelchartalignment.left:
389                         lstrects.add(new rectanglef(m_rectworking.left, m_rectworking.top + dblsplitheight * i, item.value / maxvalue * m_rectworking.width, dblsplitheight));
390                         break;
391                     case funelchartalignment.center:
392                         lstrects.add(new rectanglef(m_rectworking.left + (m_rectworking.width - (item.value / maxvalue * m_rectworking.width)) / 2, m_rectworking.top + dblsplitheight * i, item.value / maxvalue * m_rectworking.width, dblsplitheight));
393                         break;
394                     case funelchartalignment.right:
395                         lstrects.add(new rectanglef(m_rectworking.right - (item.value / maxvalue * m_rectworking.width), m_rectworking.top + dblsplitheight * i, item.value / maxvalue * m_rectworking.width, dblsplitheight));
396                         break;
397                 }
398             }
399 
400             for (int i = 0; i < lstrects.count; i++)
401             {
402                 var rect = lstrects[i];
403                 graphicspath path = new graphicspath();
404                 list<pointf> lstpoints = new list<pointf>();
405                 if (direction == funelchartdirection.up)
406                 {
407                     switch (alignment)
408                     {
409                         case funelchartalignment.left:
410                             lstpoints.add(new pointf(rect.left, rect.top));
411                             if (i != 0)
412                             {
413                                 lstpoints.add(new pointf(lstrects[i - 1].right, rect.top));
414                             }
415                             break;
416                         case funelchartalignment.center:
417                             if (i == 0)
418                             {
419                                 lstpoints.add(new pointf(rect.left + rect.width / 2, rect.top));
420                             }
421                             else
422                             {
423                                 lstpoints.add(new pointf(lstrects[i - 1].left, rect.top));
424                                 lstpoints.add(new pointf(lstrects[i - 1].right, rect.top));
425                             }
426                             break;
427                         case funelchartalignment.right:
428                             if (i == 0)
429                             {
430                                 lstpoints.add(new pointf(rect.right, rect.top));
431                             }
432                             else
433                             {
434                                 lstpoints.add(new pointf(rect.right - lstrects[i - 1].width, rect.top));
435                                 lstpoints.add(new pointf(rect.right, rect.top));
436                             }
437                             break;
438                     }
439                     lstpoints.add(new pointf(rect.right, rect.bottom - intsplitwidth));
440                     lstpoints.add(new pointf(rect.left, rect.bottom - intsplitwidth));
441                 }
442                 else
443                 {
444                     lstpoints.add(new pointf(rect.left, rect.top + intsplitwidth));
445                     lstpoints.add(new pointf(rect.right, rect.top + intsplitwidth));
446                     switch (alignment)
447                     {
448                         case funelchartalignment.left:
449                             if (i == lstrects.count - 1)
450                             {
451                                 lstpoints.add(new pointf(rect.left, rect.bottom));
452                             }
453                             else
454                             {
455                                 lstpoints.add(new pointf(lstrects[i + 1].right, rect.bottom));
456                                 lstpoints.add(new pointf(rect.left, rect.bottom));
457                             }
458                             break;
459                         case funelchartalignment.center:
460                             if (i == lstrects.count - 1)
461                             {
462                                 lstpoints.add(new pointf(rect.left + rect.width / 2, rect.bottom));
463                             }
464                             else
465                             {
466                                 lstpoints.add(new pointf(lstrects[i + 1].right, rect.bottom));
467                                 lstpoints.add(new pointf(lstrects[i + 1].left, rect.bottom));
468                             }
469                             break;
470                         case funelchartalignment.right:
471                             if (i == lstrects.count - 1)
472                             {
473                                 lstpoints.add(new pointf(rect.right, rect.bottom));
474                             }
475                             else
476                             {
477                                 lstpoints.add(new pointf(rect.right, rect.bottom));
478                                 lstpoints.add(new pointf(lstrects[i + 1].left, rect.bottom));
479                             }
480                             break;
481                     }
482                 }
483                 path.addlines(lstpoints.toarray());
484                 path.closeallfigures();
485                 // g.drawpath(new pen(new solidbrush(lstitems[i].valuecolor.value)), path);
486                 g.fillpath(new solidbrush(lstitems[i].valuecolor.value), path);
487 
488                 //写字
489                 if (itemtextalign == funelchartalignment.center)
490                 {
491                     g.drawstring(lstitems[i].text + (showvalue ? lstitems[i].value.tostring("\n" + valueformat) : ""), font, new solidbrush((lstitems[i].textforecolor == null || lstitems[i].textforecolor == color.empty || lstitems[i].textforecolor == color.transparent) ? color.white : lstitems[i].textforecolor.value), rect, new stringformat() { alignment = stringalignment.center, linealignment = stringalignment.center });
492                 }
493                 else if (itemtextalign == funelchartalignment.left)
494                 {
495                     g.drawstring(lstitems[i].text + (showvalue ? lstitems[i].value.tostring("\n" + valueformat) : ""), font, new solidbrush((lstitems[i].textforecolor == null || lstitems[i].textforecolor == color.empty || lstitems[i].textforecolor == color.transparent) ? lstitems[i].valuecolor.value : lstitems[i].textforecolor.value), new rectanglef(0, rect.top, rect.left, rect.height), new stringformat() { alignment = stringalignment.far, linealignment = stringalignment.center });
496                     g.drawline(new pen(new solidbrush((lstitems[i].textforecolor == null || lstitems[i].textforecolor == color.empty || lstitems[i].textforecolor == color.transparent) ? lstitems[i].valuecolor.value : lstitems[i].textforecolor.value)), rect.left, rect.top + rect.height / 2, rect.left + rect.width / 2, rect.top + rect.height / 2);
497                 }
498                 else
499                 {
500                     g.drawstring(lstitems[i].text + (showvalue ? lstitems[i].value.tostring("\n" + valueformat) : ""), font, new solidbrush((lstitems[i].textforecolor == null || lstitems[i].textforecolor == color.empty || lstitems[i].textforecolor == color.transparent) ? lstitems[i].valuecolor.value : lstitems[i].textforecolor.value), new rectanglef(rect.right, rect.top, this.width - rect.right, rect.height), new stringformat() { alignment = stringalignment.near, linealignment = stringalignment.center });
501                     g.drawline(new pen(new solidbrush((lstitems[i].textforecolor == null || lstitems[i].textforecolor == color.empty || lstitems[i].textforecolor == color.transparent) ? lstitems[i].valuecolor.value : lstitems[i].textforecolor.value)), rect.left + rect.width / 2, rect.top + rect.height / 2, rect.right, rect.top + rect.height / 2);
502                 }
503             }
504         }
505     }
506 }

 

最后的话

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