前提 入行已經7,8年了,一直想做一套漂亮點的自定義控制項,於是就有了本系列文章。 GitHub:https://github.com/kwwwvagaa/NetWinformControl 碼雲:https://gitee.com/kwwwvagaa/net_winform_custom_contr ...
前提
入行已經7,8年了,一直想做一套漂亮點的自定義控制項,於是就有了本系列文章。
GitHub:https://github.com/kwwwvagaa/NetWinformControl
碼雲:https://gitee.com/kwwwvagaa/net_winform_custom_control.git
如果覺得寫的還行,請點個 star 支持一下吧
麻煩博客下方點個【推薦】,謝謝
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 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