官網
http://www.hzhcontrols.com
前提
入行已經7,8年了,一直想做一套漂亮點的自定義控制元件,于是就有了本系列文章,
GitHub:https://github.com/kwwwvagaa/NetWinformControl
碼云:https://gitee.com/kwwwvagaa/net_winform_custom_control.git
如果覺得寫的還行,請點個 star 支持一下吧
歡迎前來交流探討: 企鵝群568015492 
來都來了,點個【推薦】再走吧,謝謝
NuGet
Install-Package HZH_Controls
目錄
https://www.cnblogs.com/bfyx/p/11364884.html
用處及效果

準備作業
依然使用GDI+畫圖,不懂的先百度了解下
開始
添加一些列舉
1 public 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 right13 /// </summary>14 Right15 }16 17 public enum FunelChartDirection18 {19 /// <summary>20 /// Up21 /// </summary>22 UP,23 /// <summary>24 /// Down25 /// </summary>26 Down27 }
添加一個項物體
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 set101 {102 direction = value;103 Invalidate();104 }105 }106 107 /// <summary>108 /// The alignment109 /// </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 Alignment119 {120 get { return alignment; }121 set122 {123 alignment = value;124 Invalidate();125 }126 }127 128 /// <summary>129 /// The item text align130 /// </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 ItemTextAlign140 {141 get { return itemTextAlign; }142 set143 {144 itemTextAlign = value;145 ResetWorkingRect();146 Invalidate();147 }148 }149 /// <summary>150 /// The show value151 /// </summary>152 private bool showValue = https://www.cnblogs.com/bfyx/p/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 ShowValue161 {162 get { return showValue; }163 set164 {165 showValue =https://www.cnblogs.com/bfyx/p/ value;166 Invalidate();167 }168 }169 170 171 /// <summary>172 /// The value format173 /// </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 ValueFormat183 {184 get { return valueFormat; }185 set186 {187 valueFormat = value;188 Invalidate();189 }190 }191 192 /// <summary>193 /// The m rect working194 /// </summary>195 RectangleF m_rectWorking;196 /// <summary>197 /// The m title size198 /// </summary>199 SizeF m_titleSize = SizeF.Empty;200 /// <summary>201 /// The int split width202 /// </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 = https://www.cnblogs.com/bfyx/p/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 else38 {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 else61 {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 = https://www.cnblogs.com/bfyx/p/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 else106 {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 else117 {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 else128 {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 else151 {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:[email protected] 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 items100 /// </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[] Items110 {111 get { return items; }112 set113 {114 items = value;115 Invalidate();116 }117 }118 119 /// <summary>120 /// The direction121 /// </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 Direction131 {132 get { return direction; }133 set134 {135 direction = value;136 Invalidate();137 }138 }139 140 /// <summary>141 /// The alignment142 /// </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 Alignment152 {153 get { return alignment; }154 set155 {156 alignment = value;157 Invalidate();158 }159 }160 161 /// <summary>162 /// The item text align163 /// </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 ItemTextAlign173 {174 get { return itemTextAlign; }175 set176 {177 itemTextAlign = value;178 ResetWorkingRect();179 Invalidate();180 }181 }182 /// <summary>183 /// The show value184 /// </summary>185 private bool showValue = https://www.cnblogs.com/bfyx/p/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 ShowValue194 {195 get { return showValue; }196 set197 {198 showValue =https://www.cnblogs.com/bfyx/p/ value;199 Invalidate();200 }201 }202 203 204 /// <summary>205 /// The value format206 /// </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 ValueFormat216 {217 get { return valueFormat; }218 set219 {220 valueFormat = value;221 Invalidate();222 }223 }224 225 /// <summary>226 /// The m rect working227 /// </summary>228 RectangleF m_rectWorking;229 /// <summary>230 /// The m title size231 /// </summary>232 SizeF m_titleSize = SizeF.Empty;233 /// <summary>234 /// The int split width235 /// </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 = https://www.cnblogs.com/bfyx/p/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 else312 {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 else335 {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 else372 {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 = https://www.cnblogs.com/bfyx/p/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 else422 {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 else433 {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 else443 {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 else454 {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 else465 {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 else476 {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 else499 {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 }View Code
最后的話
如果你喜歡的話,請到 https://gitee.com/kwwwvagaa/net_winform_custom_control 點個星星吧
轉載請註明出處,本文鏈接:https://www.uj5u.com/net/4896.html
標籤:WinForm

