• (七十四)c#Winform自定义控件-金字塔图表-HZHControls


    官网

    http://www.hzhcontrols.com

    前提

    入行已经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("
    " + 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("
    " + 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("
    " + 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("
    " + 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("
    " + 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("
    " + 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 点个星星吧

  • 相关阅读:
    利用DTrace实时检测MySQl
    改进MySQL Order By Rand()的低效率
    RDS for MySQL查询缓存 (Query Cache) 的设置和使用
    RDS For MySQL 字符集相关说明
    RDS for MySQL 通过 mysqlbinlog 查看 binlog 乱码
    RDS for MySQL Mysqldump 常见问题和处理
    RDS for MySQL Online DDL 使用
    RDS MySQL 表上 Metadata lock 的产生和处理
    RDS for MySQL 如何使用 Percona Toolkit
    北京已成为投融资诈骗重灾区:存好骗子公司黑名单,谨防上当!
  • 原文地址:https://www.cnblogs.com/bfyx/p/11590722.html
Copyright © 2020-2023  润新知