前提

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

GitHub:https://github.com/kwwwvagaa/NetWinformControl

码云:https://gitee.com/kwwwvagaa/net_winform_custom_control.git

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

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

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

NuGet

Install-Package HZH_Controls

目录

https://www.cnblogs.com/bfyx/p/11364884.html

用处及效果

准备工作

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

开始

添加一些枚举

 1  public 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 }

View Code

 

最后的话

如果你喜欢的话,请到 https://gitee.com/kwwwvagaa/net_winform_custom_control 点个星星吧

版权声明:本文为bfyx原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://www.cnblogs.com/bfyx/p/11590722.html