雷达分析图控件----------WinForm控件开发系列

Posted tlmbem

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了雷达分析图控件----------WinForm控件开发系列相关的知识,希望对你有一定的参考价值。

技术图片

    /// <summary>
    /// 雷达分析图控件
    /// </summary>
    [ToolboxItem(true)]
    [DefaultProperty("ChartLineItems")]
    [Description("雷达分析图控件")]
    public partial class RadarChartExt : Control
    {
        #region
        private ChartTypes chartType = ChartTypes.Circle;
        /// <summary>
        /// 雷达分析图显示类型
        /// </summary>
        [DefaultValue(ChartTypes.Circle)]
        [Description("雷达分析图显示类型")]
        public ChartTypes ChartType
        {
            get { return this.chartType; }
            set
            {
                if (this.chartType == value)
                    return;
                this.chartType = value;
                this.Invalidate();
            }
        }

        private ChartAnchors chartAnchor = ChartAnchors.Left;
        /// <summary>
        /// 分析图布局
        /// </summary>
        [DefaultValue(ChartAnchors.Left)]
        [Description("分析图布局")]
        public ChartAnchors ChartAnchor
        {
            get { return this.chartAnchor; }
            set
            {
                if (this.chartAnchor == value)
                    return;
                this.chartAnchor = value;
                this.InitializeRectangle();
                this.Invalidate();
            }
        }

        private DescriptionAnchors descriptionAnchor = DescriptionAnchors.Bottom;
        /// <summary>
        /// 描述布局
        /// </summary>
        [DefaultValue(DescriptionAnchors.Bottom)]
        [Description("描述布局")]
        public DescriptionAnchors DescriptionAnchor
        {
            get { return this.descriptionAnchor; }
            set
            {
                if (this.descriptionAnchor == value)
                    return;
                this.descriptionAnchor = value;
                this.InitializeRectangle();
                this.Invalidate();
            }
        }

        private Size chartSize = new Size(200, 200);
        /// <summary>
        /// 分析图Size
        /// </summary>
        [DefaultValue(typeof(Size), "200, 200")]
        [Description("分析图Size")]
        public Size ChartSize
        {
            get { return this.chartSize; }
            set
            {
                if (this.chartSize == value || value.Width < 2 || value.Height < 2)
                    return;
                this.chartSize = value;
                this.InitializeRectangle();
                this.Invalidate();
            }
        }

        private int loopCount = 5;
        /// <summary>
        /// 环形数量
        /// </summary>
        [DefaultValue(5)]
        [Description("环形数量")]
        public int LoopCount
        {
            get { return this.loopCount; }
            set
            {
                if (this.loopCount == value || value < 1)
                    return;
                this.loopCount = value;
                this.InitializeLoop();
                this.InitializeRectangle();
                this.Invalidate();
            }
        }

        private float loopInterval = 20f;
        /// <summary>
        /// 环形间隔值
        /// </summary>
        [DefaultValue(20f)]
        [Description("环形间隔值")]
        public float LoopInterval
        {
            get { return this.loopInterval; }
            set
            {
                if (this.loopInterval == value || value < 0f)
                    return;
                this.loopInterval = value;
                this.InitializeRectangle();
                this.Invalidate();
            }
        }

        private int loopBorderthickness = 1;
        /// <summary>
        /// 环形线厚度
        /// </summary>
        [DefaultValue(1)]
        [Description("环形线厚度")]
        public int LoopBorderthickness
        {
            get { return this.loopBorderthickness; }
            set
            {
                if (this.loopBorderthickness == value || this.loopBorderthickness < 1)
                    return;
                this.loopBorderthickness = value;
                this.Invalidate();
            }
        }

        private Color loopBorderColor = Color.FromArgb(224, 224, 224);
        /// <summary>
        /// 环形线颜色
        /// </summary>
        [DefaultValue(typeof(Color), "224, 224, 224")]
        [Description("环形线颜色")]
        [Editor(typeof(ColorEditorExt), typeof(System.Drawing.Design.UITypeEditor))]
        public Color LoopBorderColor
        {
            get { return this.loopBorderColor; }
            set
            {
                if (this.loopBorderColor == value)
                    return;
                this.loopBorderColor = value;
                this.Invalidate();
            }
        }

        private Color loopOddBackColor = Color.FromArgb(62, 224, 224, 224);
        /// <summary>
        /// 奇数环形背景颜色
        /// </summary>
        [DefaultValue(typeof(Color), "62, 224, 224, 224")]
        [Description("奇数环形背景颜色")]
        [Editor(typeof(ColorEditorExt), typeof(System.Drawing.Design.UITypeEditor))]
        public Color LoopOddBackColor
        {
            get { return this.loopOddBackColor; }
            set
            {
                if (this.loopOddBackColor == value)
                    return;
                this.loopOddBackColor = value;
                this.Invalidate();
            }
        }

        private Color loopEvenBackColor = Color.FromArgb(255, 255, 255);
        /// <summary>
        /// 偶数环形背景颜色
        /// </summary>
        [DefaultValue(typeof(Color), "255, 255, 255")]
        [Description("偶数环形背景颜色")]
        [Editor(typeof(ColorEditorExt), typeof(System.Drawing.Design.UITypeEditor))]
        public Color LoopEvenBackColor
        {
            get { return this.loopEvenBackColor; }
            set
            {
                if (this.loopEvenBackColor == value)
                    return;
                this.loopEvenBackColor = value;
                this.Invalidate();
            }
        }

        private Color loopScaleTextColor = Color.FromArgb(128, 128, 128);
        /// <summary>
        /// 环形刻度文本颜色
        /// </summary>
        [DefaultValue(typeof(Color), "128, 128, 128")]
        [Description("环形刻度文本颜色")]
        [Editor(typeof(ColorEditorExt), typeof(System.Drawing.Design.UITypeEditor))]
        public Color LoopScaleTextColor
        {
            get { return this.loopScaleTextColor; }
            set
            {
                if (this.loopScaleTextColor == value)
                    return;
                this.loopScaleTextColor = value;
                this.Invalidate();
            }
        }

        private Color loopLineTextColor = Color.FromArgb(0, 192, 192);
        /// <summary>
        /// 环形选项文本颜色
        /// </summary>
        [DefaultValue(typeof(Color), "0, 192, 192")]
        [Description("环形选项文本颜色")]
        [Editor(typeof(ColorEditorExt), typeof(System.Drawing.Design.UITypeEditor))]
        public Color LoopLineTextColor
        {
            get { return this.loopLineTextColor; }
            set
            {
                if (this.loopLineTextColor == value)
                    return;
                this.loopLineTextColor = value;
                this.Invalidate();
            }
        }

        private bool loopLineMaxValueShow = false;
        /// <summary>
        /// 动画中是否显示环形选项最大值高亮背景颜色
        /// </summary>
        [DefaultValue(false)]
        [Description("动画中是否显示环形选项最大值高亮背景颜色")]
        public bool LoopLineMaxValueShow
        {
            get { return this.loopLineMaxValueShow; }
            set
            {
                if (this.loopLineMaxValueShow == value)
                    return;
                this.loopLineMaxValueShow = value;
                this.Invalidate();
            }
        }

        private Color loopLineMaxValueTextColor = Color.FromArgb(255, 128, 128);
        /// <summary>
        /// 环形选项最大值高亮背景颜色
        /// </summary>
        [DefaultValue(typeof(Color), "255, 128, 128")]
        [Description("环形选项最大值高亮背景颜色")]
        [Editor(typeof(ColorEditorExt), typeof(System.Drawing.Design.UITypeEditor))]
        public Color LoopLineMaxValueTextColor
        {
            get { return this.loopLineMaxValueTextColor; }
            set
            {
                if (this.loopLineMaxValueTextColor == value)
                    return;
                this.loopLineMaxValueTextColor = value;
                this.Invalidate();
            }
        }

        private bool loopLineMinValueShow = false;
        /// <summary>
        /// 动画中是否显示环形选项最小值高亮背景颜色
        /// </summary>
        [DefaultValue(false)]
        [Description("动画中是否显示环形选项最小值高亮背景颜色")]
        public bool LoopLineMinValueShow
        {
            get { return this.loopLineMinValueShow; }
            set
            {
                if (this.loopLineMinValueShow == value)
                    return;
                this.loopLineMinValueShow = value;
                this.Invalidate();
            }
        }

        private Color loopLineMinValueTextColor = Color.FromArgb(65, 105, 225);
        /// <summary>
        /// 环形选项最小值高亮背景颜色
        /// </summary>
        [DefaultValue(typeof(Color), "65, 105, 225")]
        [Description("环形选项最小值高亮背景颜色")]
        [Editor(typeof(ColorEditorExt), typeof(System.Drawing.Design.UITypeEditor))]
        public Color LoopLineMinValueTextColor
        {
            get { return this.loopLineMinValueTextColor; }
            set
            {
                if (this.loopLineMinValueTextColor == value)
                    return;
                this.loopLineMinValueTextColor = value;
                this.Invalidate();
            }
        }

        private bool optionAreaShow = true;
        /// <summary>
        /// 是否显示选项列表
        /// </summary>
        [DefaultValue(true)]
        [Description("是否显示选项列表")]
        public bool OptionAreaShow
        {
            get { return this.optionAreaShow; }
            set
            {
                if (this.optionAreaShow == value)
                    return;
                this.optionAreaShow = value;
                this.InitializeRectangle();
                this.Invalidate();
            }
        }

        private int optionAreaWidth = 40;
        /// <summary>
        /// 选项列表区域宽度
        /// </summary>
        [DefaultValue(40)]
        [Description("选项列表区域宽度")]
        public int OptionAreaWidth
        {
            get { return this.optionAreaWidth; }
            set
            {
                if (this.optionAreaWidth == value || this.optionAreaWidth < 0)
                    return;
                this.optionAreaWidth = value;
                this.InitializeRectangle();
                this.Invalidate();
            }
        }

        private int descriptionAreaHeight = 30;
        /// <summary>
        /// 文本区域高度
        /// </summary>
        [DefaultValue(30)]
        [Description("文本区域高度")]
        public int DescriptionAreaHeight
        {
            get { return this.descriptionAreaHeight; }
            set
            {
                if (this.descriptionAreaHeight == value || this.descriptionAreaHeight < 0)
                    return;
                this.descriptionAreaHeight = value;
                this.InitializeRectangle();
                this.Invalidate();
            }
        }

        private Color optionTextColor = Color.FromArgb(128, 128, 128);
        /// <summary>
        /// 选项文本颜色
        /// </summary>
        [DefaultValue(typeof(Color), "128, 128, 128")]
        [Description("选项文本颜色")]
        [Editor(typeof(ColorEditorExt), typeof(System.Drawing.Design.UITypeEditor))]
        public Color OptionTextColor
        {
            get { return this.optionTextColor; }
            set
            {
                if (this.optionTextColor == value)
                    return;
                this.optionTextColor = value;
                this.Invalidate();
            }
        }

        private Color optionTipTextColor = Color.FromArgb(255, 255, 255);
        /// <summary>
        /// 选项提示文本颜色
        /// </summary>
        [DefaultValue(typeof(Color), "255, 255, 255")]
        [Description("选项提示文本颜色")]
        [Editor(typeof(ColorEditorExt), typeof(System.Drawing.Design.UITypeEditor))]
        public Color OptionTipTextColor
        {
            get { return this.optionTipTextColor; }
            set
            {
                if (this.optionTipTextColor == value)
                    return;
                this.optionTipTextColor = value;
                this.Invalidate();
            }
        }

        private string title = "";
        /// <summary>
        /// 标题
        /// </summary>
        [DefaultValue("")]
        [Description("标题")]
        public string Title
        {
            get { return this.title; }
            set
            {
                if (this.title == value)
                    return;
                this.title = value;
                this.Invalidate();
            }
        }

        private Color titleColor = Color.FromArgb(219, 112, 147);
        /// <summary>
        /// 标题颜色
        /// </summary>
        [DefaultValue(typeof(Color), "219, 112, 147")]
        [Description("标题颜色")]
        [Editor(typeof(ColorEditorExt), typeof(System.Drawing.Design.UITypeEditor))]
        public Color TitleColor
        {
            get { return this.titleColor; }
            set
            {
                if (this.titleColor == value)
                    return;
                this.titleColor = value;
                this.Invalidate();
            }
        }

        private ChartLoopCollection chartLoopCollection;
        /// <summary>
        /// 分析图环形配置集合
        /// </summary>
        [Browsable(false)]
        [Description("分析图环形配置集合")]
        public ChartLoopCollection ChartLoopItems
        {
            get
            {
                if (this.chartLoopCollection == null)
                    this.chartLoopCollection = new ChartLoopCollection(this);
                return this.chartLoopCollection;
            }
        }

        private ChartLineCollection chartLineCollection;
        /// <summary>
        /// 分析图角度线配置集合
        /// </summary>
        [Description("分析图角度线配置集合")]
        [DesignerSerializationVisibility(DesignerSerializationVisibility.Content)]
        public ChartLineCollection ChartLineItems
        {
            get
            {
                if (this.chartLineCollection == null)
                    this.chartLineCollection = new ChartLineCollection(this);
                return this.chartLineCollection;
            }
        }

        private ChartItemCollection chartItemOptionCollection;
        /// <summary>
        /// 分析图选项数据集合
        /// </summary>
        [Browsable(false)]
        [Description("分析图选项数据集合")]
        [DesignerSerializationVisibility(DesignerSerializationVisibility.Content)]
        public ChartItemCollection ChartItemItems
        {
            get
            {
                if (this.chartItemOptionCollection == null)
                    this.chartItemOptionCollection = new ChartItemCollection(this);
                return this.chartItemOptionCollection;
            }
        }

        protected override Size DefaultSize
        {
            get
            {
                return new Size(150, 150); ;
            }
        }
        public override string Text
        {
            get
            {
                return base.Text;
            }
            set
            {
                if (base.Text == value)
                    return;
                base.Text = value;
                this.Invalidate();
            }
        }
        protected override Padding DefaultPadding
        {
            get
            {
                return new Padding(10);
            }
        }
        public new Padding Padding
        {
            get
            {
                return base.Padding;
            }
            set
            {
                if (this.Padding == value)
                    return;
                this.Padding = value;
                this.InitializeRectangle();
                this.Invalidate();
            }
        }

        /// <summary>
        /// 是否启用动画变换
        /// </summary>
        private bool isAnimation = false;
        /// <summary>
        /// 雷达分析图信息
        /// </summary>
        private ChartRectangle ChartMainRect;
        /// <summary>
        /// 分析图选项状态
        /// </summary>
        private ChartItemMoveStatuss ChartItemMoveStatus = ChartItemMoveStatuss.Normal;
        /// <summary>
        /// 默认开始角度
        /// </summary>
        private float DefaultAngle = 270f;
        /// <summary>
        /// 选中环形对角线
        /// </summary>
        private ItemLine SelectItemLine = null;
        /// <summary>
        /// 动画播放定时器
        /// </summary>
        private AnimationTimer animationTimer;
        #endregion

        public RadarChartExt()
        {
            SetStyle(ControlStyles.UserPaint, true);
            SetStyle(ControlStyles.AllPaintingInWmPaint, true);
            SetStyle(ControlStyles.OptimizedDoubleBuffer, true);
            SetStyle(ControlStyles.ResizeRedraw, true);
            SetStyle(ControlStyles.SupportsTransparentBackColor, true);
            InitializeComponent();
            this.ChartMainRect = new ChartRectangle();
            this.InitializeLoop();
            this.InitializeRectangle();

        }

        #region 重写

        protected override void OnPaint(System.Windows.Forms.PaintEventArgs e)
        {
            base.OnPaint(e);

            if (this.ChartLineItems.Count < 3)
                return;

            Graphics g = e.Graphics;
            SmoothingMode sm = g.SmoothingMode;
            g.SmoothingMode = SmoothingMode.AntiAlias;

            GraphicsPath loop_gp = new GraphicsPath();
            #region 环形

            Pen loopBorder_pen = new Pen(this.LoopBorderColor, this.LoopBorderthickness);
            SolidBrush loopoddback_sb = new SolidBrush(this.LoopOddBackColor);
            SolidBrush loopevenback_sb = new SolidBrush(this.LoopEvenBackColor);
            SolidBrush looplinetext_sb = new SolidBrush(this.LoopLineTextColor);
            SolidBrush looplinemaxvaluetext_sb = this.isAnimation && this.LoopLineMaxValueShow ? new SolidBrush(this.LoopLineMaxValueTextColor) : null;
            SolidBrush looplineminvaluetext_sb = this.isAnimation && this.LoopLineMinValueShow ? new SolidBrush(this.LoopLineMinValueTextColor) : null;

            for (int i = 0; i < this.ChartLoopItems.Count; i++)
            {
                if (this.ChartLoopItems[i].DataPoints.Length < 3)
                    continue;

                if (this.ChartType == ChartTypes.Rhombus)
                {
                    loop_gp.Reset();
                    loop_gp.AddPolygon(this.ChartLoopItems[i].DataPoints);
                    loop_gp.CloseFigure();
                    g.DrawPath(loopBorder_pen, loop_gp);

                    loop_gp.Reset();
                    loop_gp.AddPolygon(this.ChartLoopItems[i].DataPoints);
                    if (i > 0)
                    {
                        loop_gp.StartFigure();
                        loop_gp.AddPolygon(this.ChartLoopItems[i - 1].DataPoints);
                    }
                    g.FillPath((i % 2 == 0) ? loopoddback_sb : loopevenback_sb, loop_gp);
                }
                else
                {
                    loop_gp.Reset();
                    loop_gp.AddEllipse(new RectangleF(this.ChartLoopItems[i].LoopCenter.X - this.ChartLoopItems[i].LoopRadius, this.ChartLoopItems[i].LoopCenter.Y - this.ChartLoopItems[i].LoopRadius, this.ChartLoopItems[i].LoopRadius * 2, this.ChartLoopItems[i].LoopRadius * 2));
                    g.DrawPath(loopBorder_pen, loop_gp);

                    loop_gp.Reset();
                    loop_gp.AddEllipse(new RectangleF(this.ChartLoopItems[i].LoopCenter.X - this.ChartLoopItems[i].LoopRadius, this.ChartLoopItems[i].LoopCenter.Y - this.ChartLoopItems[i].LoopRadius, this.ChartLoopItems[i].LoopRadius * 2, this.ChartLoopItems[i].LoopRadius * 2));
                    if (i > 0)
                    {
                        loop_gp.StartFigure();
                        loop_gp.AddEllipse(new RectangleF(this.ChartLoopItems[i - 1].LoopCenter.X - this.ChartLoopItems[i - 1].LoopRadius, this.ChartLoopItems[i - 1].LoopCenter.Y - this.ChartLoopItems[i - 1].LoopRadius, this.ChartLoopItems[i - 1].LoopRadius * 2, this.ChartLoopItems[i - 1].LoopRadius * 2));
                    }
                    g.FillPath((i % 2 == 0) ? loopoddback_sb : loopevenback_sb, loop_gp);
                }
            }

            #endregion

            #region 角度线
            float maxValue = 0f;
            float minValue = 0f;
            List<int> maxIndexList = new List<int>();
            List<int> minIndexList = new List<int>();

            if (this.LoopLineMaxValueShow && this.ChartItemItems.Count > 0)
            {
                for (int i = 0; i < this.ChartItemItems[0].ItemDataTargrt.Length; i++)
                {
                    if (i == 0)
                    {
                        maxValue = this.ChartItemItems[0].ItemDataTargrt[0];
                    }
                    if (this.ChartItemItems[0].ItemDataTargrt[i] > maxValue)
                    {
                        maxValue = this.ChartItemItems[0].ItemDataTargrt[i];
                        maxIndexList.Clear();
                        maxIndexList.Add(i);
                    }
                    else if (this.ChartItemItems[0].ItemDataTargrt[i] == maxValue)
                    {
                        maxIndexList.Add(i);
                    }
                }
            }

            if (this.LoopLineMinValueShow && this.ChartItemItems.Count > 0)
            {
                for (int i = 0; i < this.ChartItemItems[0].ItemDataTargrt.Length; i++)
                {
                    if (i == 0)
                    {
                        minValue = this.ChartItemItems[0].ItemDataTargrt[0];
                    }
                    if (this.ChartItemItems[0].ItemDataTargrt[i] < minValue)
                    {
                        minValue = this.ChartItemItems[0].ItemDataTargrt[i];
                        minIndexList.Clear();
                        minIndexList.Add(i);
                    }
                    else if (this.ChartItemItems[0].ItemDataTargrt[i] == minValue)
                    {
                        minIndexList.Add(i);
                    }
                }
            }

            for (int i = 0; i < this.ChartLineItems.Count; i++)
            {
                string loopline_txt = this.ChartLineItems[i].LineText;
                SizeF loopline_textsize = g.MeasureString(loopline_txt, this.Font);
                PointF loopline_txt_point = this.ChartLineItems[i].LineEndPoint;
                if (this.ChartLineItems[i].LineAngle == 0)
                {
                    loopline_txt_point.Y = loopline_txt_point.Y - loopline_textsize.Height / 2;
                }
                else if (this.ChartLineItems[i].LineAngle < 90)
                {

                }
                else if (this.ChartLineItems[i].LineAngle == 90)
                {
                    loopline_txt_point.X = loopline_txt_point.X - loopline_textsize.Width / 2;
                }
                else if (this.ChartLineItems[i].LineAngle < 180)
                {
                    loopline_txt_point.X = loopline_txt_point.X - loopline_textsize.Width;
                }
                else if (this.ChartLineItems[i].LineAngle == 180)
                {
                    loopline_txt_point.Y = loopline_txt_point.Y - loopline_textsize.Height / 2;
                    loopline_txt_point.X = loopline_txt_point.X - loopline_textsize.Width;
                }
                else if (this.ChartLineItems[i].LineAngle < 270)
                {
                    loopline_txt_point.Y = loopline_txt_point.Y - loopline_textsize.Height;
                    loopline_txt_point.X = loopline_txt_point.X - loopline_textsize.Width;
                }
                else if (this.ChartLineItems[i].LineAngle == 270)
                {
                    loopline_txt_point.Y = loopline_txt_point.Y - loopline_textsize.Height;
                    loopline_txt_point.X = loopline_txt_point.X - loopline_textsize.Width / 2;
                }
                else if (this.ChartLineItems[i].LineAngle < 360)
                {
                    loopline_txt_point.Y = loopline_txt_point.Y - loopline_textsize.Height;
                }

                SolidBrush sb = looplinetext_sb;
                if (this.isAnimation)
                {
                    if (maxIndexList.IndexOf(i) != -1)
                    {
                        sb = looplinemaxvaluetext_sb;
                    }
                    if (minIndexList.IndexOf(i) != -1)
                    {
                        sb = looplineminvaluetext_sb;
                    }
                }

                g.DrawString(loopline_txt, this.Font, sb, loopline_txt_point);

            }

            for (int j = 0; j < this.ChartLineItems.Count; j++)
            {
                g.DrawLine(loopBorder_pen, this.ChartLineItems[j].LoopCenter, this.ChartLineItems[j].LineEndPoint);
            }

            #endregion

            loop_gp.Dispose();
            loopBorder_pen.Dispose();
            loopoddback_sb.Dispose();
            loopevenback_sb.Dispose();
            looplinetext_sb.Dispose();
            if (looplinemaxvaluetext_sb != null)
                looplinemaxvaluetext_sb.Dispose();
            if (looplineminvaluetext_sb != null)
                looplineminvaluetext_sb.Dispose();
            #region 数据
            SolidBrush databack_sb = new SolidBrush(Color.White);
            if (this.ChartItemItems.Count > 0)
            {
                GraphicsPath databack_gp = new GraphicsPath();
                Pen databorder_pen = new Pen(Color.White, 1);
                Pen datadot_pen = new Pen(Color.White, 1);

                for (int i = 0; i < this.ChartItemItems.Count; i++)
                {
                    if (this.ChartItemItems[i].ItemDataPoints.Length < 2)
                        continue;

                    databack_gp.Reset();
                    databack_gp.AddPolygon(this.ChartItemItems[i].ItemDataPoints);
                    databack_gp.CloseFigure();

                    databack_sb.Color = Color.FromArgb(50, this.ChartItemItems[i].ItemBackColor);
                    g.FillPath(databack_sb, databack_gp);

                    databorder_pen.Color = this.ChartItemItems[i].ItemBackColor;
                    g.DrawPath(databorder_pen, databack_gp);

                    datadot_pen.Color = this.ChartItemItems[i].ItemBackColor;
                    for (int j = 0; j < this.ChartItemItems[i].ItemDataPoints.Length; j++)
                    {
                        g.DrawEllipse(datadot_pen, this.ChartItemItems[i].ItemDataRectF[j]);
                    }
                }
                databack_gp.Dispose();
                databorder_pen.Dispose();
                datadot_pen.Dispose();

            }

            #endregion

            g.SmoothingMode = sm;

            #region 数据选项
            if (this.OptionAreaShow)
            {
                float desc_padding = 5;
                float descitem_height = 0;

                SolidBrush descitem_sb = new SolidBrush(Color.White);
                SolidBrush desctext_sb = new SolidBrush(this.OptionTextColor);
                for (int i = 0; i < this.ChartItemItems.Count; i++)
                {
                    descitem_sb.Color = this.ChartItemItems[i].ItemBackColor;
                    SizeF desc_size = g.MeasureString(this.ChartItemItems[i].ItemText, this.Font);
                    RectangleF desc_item_rect = new RectangleF(this.ChartMainRect.OptionRect.X + desc_padding, this.ChartMainRect.OptionRect.Y + descitem_height, 20, 10);
                    RectangleF desctxt_rect = new RectangleF(this.ChartMainRect.OptionRect.X + desc_padding + desc_item_rect.Width + 5, this.ChartMainRect.OptionRect.Y + descitem_height, this.ChartMainRect.OptionRect.Width - desc_padding - desc_item_rect.Width - 5, desc_size.Height);

                    g.FillRectangle(descitem_sb, desc_item_rect);
                    g.DrawString(this.ChartItemItems[i].ItemText, this.Font, desctext_sb, desctxt_rect);

                    descitem_height += desc_size.Height + desc_padding;
                }

                descitem_sb.Dispose();
                desctext_sb.Dispose();
            }
            #endregion

            #region 刻度
            SolidBrush loopscaletext_sb = new SolidBrush(this.LoopScaleTextColor);
            Pen loopscaletext_pen = new Pen(this.LoopScaleTextColor);
            for (int i = 0; i < this.ChartLoopItems.Count; i++)
            {
                string loopscale_txt = (this.LoopInterval * (i + 1)).ToString();
                SizeF loopscale_size = g.MeasureString(loopscale_txt, this.Font);
                g.DrawLine(loopscaletext_pen, this.ChartLoopItems[i].DataPoints[0].X, this.ChartLoopItems[i].DataPoints[0].Y, this.ChartLoopItems[i].DataPoints[0].X + 3, this.ChartLoopItems[i].DataPoints[0].Y);

                g.DrawString(loopscale_txt, this.Font, loopscaletext_sb, new RectangleF(this.ChartLoopItems[i].DataPoints[0].X + 5, this.ChartLoopItems[i].DataPoints[0].Y - loopscale_size.Height / 2, loopscale_size.Width, loopscale_size.Height));
            }
            loopscaletext_sb.Dispose();
            #endregion

            #region 数据点提示

            if (this.ChartItemMoveStatus == ChartItemMoveStatuss.Enter)
            {
                if (this.SelectItemLine != null)
                {
                    float datadottipback_padding = 2;
                    databack_sb.Color = Color.FromArgb(100, this.ChartItemItems[this.SelectItemLine.ItemIndex].ItemBackColor);
                    Pen tipborder_pen = new Pen(this.ChartItemItems[this.SelectItemLine.ItemIndex].ItemBackColor);
                    SolidBrush datadottiptext_sb = new SolidBrush(this.OptionTipTextColor);
                    StringFormat datadottiptext_sf = new StringFormat() { Alignment = StringAlignment.Center, LineAlignment = StringAlignment.Center };

                    string datadottip_txt = this.SelectItemLine.LineIndex >= this.ChartItemItems[this.SelectItemLine.ItemIndex].ItemDataTargrt.Count() ? " " : this.ChartItemItems[this.SelectItemLine.ItemIndex].ItemDataTargrt[this.SelectItemLine.LineIndex].ToString();
                    SizeF datadottiptxt_size = g.MeasureString(datadottip_txt, this.Font);
                    RectangleF datadottip_rect = new RectangleF(this.ChartItemItems[this.SelectItemLine.ItemIndex].ItemDataRectF[this.SelectItemLine.LineIndex].X - (datadottiptxt_size.Width + datadottipback_padding * 2) / 2, this.ChartItemItems[this.SelectItemLine.ItemIndex].ItemDataRectF[this.SelectItemLine.LineIndex].Y - datadottiptxt_size.Height - datadottipback_padding * 3, datadottiptxt_size.Width + datadottipback_padding * 2, datadottiptxt_size.Height + datadottipback_padding * 2);

                    g.FillRectangle(databack_sb, datadottip_rect);
                    g.DrawRectangle(tipborder_pen, datadottip_rect.X, datadottip_rect.Y, datadottip_rect.Width, datadottip_rect.Height);
                    g.DrawString(datadottip_txt, this.Font, datadottiptext_sb, datadottip_rect, datadottiptext_sf);

                    datadottiptext_sb.Dispose();
                    tipborder_pen.Dispose();
                    datadottiptext_sf.Dispose();
                }
            }

            #endregion
            databack_sb.Dispose();

            #region 标题
            SolidBrush title_sb = new SolidBrush(this.TitleColor);
            StringFormat title_sf = new StringFormat() { Alignment = StringAlignment.Center };

            g.DrawString(this.Title, this.Font, title_sb, this.ChartMainRect.DescriptionRect, title_sf);
            title_sb.Dispose();
            title_sf.Dispose();
            #endregion

        }

        protected override void OnResize(EventArgs e)
        {
            this.InitializeRectangle();
            base.OnResize(e);
        }

        protected override void OnMouseMove(MouseEventArgs e)
        {
            base.OnMouseMove(e);
            if (this.ChartMainRect.ChartRect.Contains(e.Location))
            {
                for (int i = 0; i < this.ChartItemItems.Count; i++)
                {
                    for (int j = 0; j < this.ChartItemItems[i].ItemDataRectF.Length; j++)
                    {
                        if (this.ChartItemItems[i].ItemDataRectF[j].Contains(e.Location))
                        {
                            this.SelectItemLine = new ItemLine() { ItemIndex = i, LineIndex = j };
                            this.ChartItemMoveStatus = ChartItemMoveStatuss.Enter;
                            this.Invalidate();
                            return;
                        }
                    }
                }
                if (this.ChartItemMoveStatus != ChartItemMoveStatuss.Normal)
                {
                    this.ChartItemMoveStatus = ChartItemMoveStatuss.Normal;
                    this.Invalidate();
                }
            }
        }
        protected override void OnMouseLeave(EventArgs e)
        {
            base.OnMouseLeave(e);
            if (this.ChartItemMoveStatus != ChartItemMoveStatuss.Normal)
            {
                this.ChartItemMoveStatus = ChartItemMoveStatuss.Normal;
                this.Invalidate();
            }
        }
        protected override void Dispose(bool disposing)
        {
            if (disposing && (components != null))
            {
                components.Dispose();
                if (this.animationTimer != null)
                    this.animationTimer.Dispose();
            }
            base.Dispose(disposing);
        }
        #endregion

        #region 公开

        /// <summary>
        /// 动画更新数据
        /// </summary>
        /// <param name="AnimationData"></param>
        public void AnimationChange(List<ChartAnimationItem> AnimationData)
        {
            if (AnimationData.Count != this.ChartItemItems.Count)
                return;

            bool ischange = false;
            for (int i = 0; i < this.ChartItemItems.Count; i++)
            {
                for (int j = 0; j < this.ChartItemItems[i].ItemDataCurrent.Length; j++)
                {
                    if (this.ChartItemItems[i].ItemDataCurrent[j] != AnimationData[i].ItemData[j])
                    {
                        ischange = true;
                        break;
                    }
                }
            }
            if (ischange)
            {
                if (this.animationTimer == null)
                {
                    this.CreateAnimation();
                    this.isAnimation = true;
                }
                this.animationTimer.Stop();
                for (int i = 0; i < this.ChartItemItems.Count; i++)
                {
                    this.ChartItemItems[i].ItemDataBefore = this.ChartItemItems[i].ItemDataCurrent;
                    this.ChartItemItems[i].ItemDataTargrt = AnimationData[i].ItemData;
                }
                this.animationTimer.Start(true, 0);
            }
        }

        /// <summary>
        /// 绑定数据后更新
        /// </summary>
        public void DataBind()
        {
            for (int i = 0; i < this.ChartItemItems.Count; i++)
            {
                this.ChartItemItems[i].ItemDataBefore = this.ChartItemItems[i].ItemDataCurrent;
                this.ChartItemItems[i].ItemDataTargrt = this.ChartItemItems[i].ItemDataCurrent;
                this.InitializeRectangle();
                this.Invalidate();
            }
        }
        #endregion

        #region 私有
        /// <summary>
        /// 初始化环形
        /// </summary>
        private void InitializeLoop()
        {
            this.ChartLoopItems.Clear();
            for (int i = 0; i < this.LoopCount; i++)
            {
                this.ChartLoopItems.Add(new ChartLoop());
            }
        }

        /// <summary>
        /// 初始化控件布局
        /// </summary>
        public void InitializeRectangle()
        {
            if (this.ChartLineItems.Count < 3)
                return;

            float now_radius = 0f;
            float now_angle = this.DefaultAngle;
            Rectangle rect = new Rectangle(this.ClientRectangle.X + this.Padding.Left, this.ClientRectangle.Y + this.Padding.Top, this.ClientRectangle.Width - this.Padding.Left - this.Padding.Right, this.ClientRectangle.Height - this.Padding.Top - this.Padding.Bottom);
            Rectangle option_rect = new Rectangle();
            int ptionarea_width = !this.OptionAreaShow ? 0 : this.OptionAreaWidth;
            #region Rect
            if (DescriptionAnchor == DescriptionAnchors.Top)
            {
                this.ChartMainRect.DescriptionRect = new RectangleF(rect.X, rect.Y, rect.Width, this.DescriptionAreaHeight);
                if (this.ChartAnchor == ChartAnchors.Left)
                {
                    this.ChartMainRect.OptionRect = !this.OptionAreaShow ? option_rect : new RectangleF(rect.Right - ptionarea_width, rect.Y + this.DescriptionAreaHeight, ptionarea_width, rect.Height - this.DescriptionAreaHeight);
                    this.ChartMainRect.ChartRect = new RectangleF(rect.X + (rect.Width - ptionarea_width - this.ChartSize.Width) / 2, rect.Y + this.DescriptionAreaHeight + (rect.Height - this.ChartSize.Height) / 2, this.ChartSize.Width, this.ChartSize.Height);
                }
                else
                {
                    this.ChartMainRect.OptionRect = !this.OptionAreaShow ? option_rect : new RectangleF(rect.X, rect.Y + this.DescriptionAreaHeight, ptionarea_width, rect.Height - this.DescriptionAreaHeight);
                    this.ChartMainRect.ChartRect = new RectangleF(rect.X + ptionarea_width + (rect.Width - ptionarea_width - this.ChartSize.Width) / 2, rect.Y + this.DescriptionAreaHeight + (rect.Height - this.ChartSize.Height) / 2, this.ChartSize.Width, this.ChartSize.Height);
                }
            }
            else
            {
                this.ChartMainRect.DescriptionRect = new RectangleF(rect.X, rect.Bottom - this.DescriptionAreaHeight, rect.Width, this.DescriptionAreaHeight);
                if (this.ChartAnchor == ChartAnchors.Left)
                {
                    this.ChartMainRect.OptionRect = !this.OptionAreaShow ? option_rect : new RectangleF(rect.Right - ptionarea_width, rect.Y, ptionarea_width, rect.Height - this.DescriptionAreaHeight);
                    this.ChartMainRect.ChartRect = new RectangleF(rect.X + (rect.Width - ptionarea_width - this.ChartSize.Width) / 2, rect.Y + (rect.Height - this.ChartSize.Height) / 2, this.ChartSize.Width, this.ChartSize.Height);
                }
                else
                {
                    this.ChartMainRect.OptionRect = !this.OptionAreaShow ? option_rect : new RectangleF(rect.X, rect.Y, ptionarea_width, rect.Height - this.DescriptionAreaHeight);
                    this.ChartMainRect.ChartRect = new RectangleF(rect.X + ptionarea_width + (rect.Width - ptionarea_width - this.ChartSize.Width) / 2, rect.Y + (rect.Height - this.ChartSize.Height) / 2, this.ChartSize.Width, this.ChartSize.Height);
                }
            }
            #endregion

            PointF chart_center = new PointF(this.ChartMainRect.ChartRect.X + this.ChartMainRect.ChartRect.Width / 2, this.ChartMainRect.ChartRect.Y + this.ChartMainRect.ChartRect.Height / 2);
            float chart_radius = Math.Min(this.ChartMainRect.ChartRect.Width, this.ChartMainRect.ChartRect.Height) / 2;

            #region 圆环
            for (int i = 0; i < this.ChartLoopItems.Count; i++)
            {
                this.ChartLoopItems[i].DataPoints = new PointF[this.ChartLineItems.Count];

                now_angle = this.DefaultAngle;
                now_radius = chart_radius / (this.ChartLoopItems.Count) * (i + 1);
                this.ChartLoopItems[i].LoopCenter = chart_center;
                this.ChartLoopItems[i].LoopRadius = now_radius;

                for (int j = 0; j < this.ChartLineItems.Count; j++)
                {
                    now_angle = this.DefaultAngle + 360f / this.ChartLineItems.Count * j;
                    if (now_angle > 360)
                        now_angle -= 360;

                    this.ChartLoopItems[i].DataPoints[j] = CalculatePointForAngle(chart_center, now_radius, now_angle);
                }
            }

            #endregion

            #region 角度线
            now_angle = this.DefaultAngle;
            now_radius = chart_radius / (this.ChartLoopItems.Count) * this.ChartLoopItems.Count;

            for (int j = 0; j < this.ChartLineItems.Count; j++)
            {
                now_angle = this.DefaultAngle + 360f / this.ChartLineItems.Count * j;
                if (now_angle > 360)
                    now_angle -= 360;

                this.ChartLineItems[j].LoopCenter = chart_center;
                this.ChartLineItems[j].LoopRadius = now_radius;
                this.ChartLineItems[j].LineAngle = now_angle;
                this.ChartLineItems[j].LineEndPoint = CalculatePointForAngle(chart_center, now_radius, now_angle);
            }
            #endregion

            #region 数据
            for (int i = 0; i < this.ChartItemItems.Count; i++)
            {
                this.ChartItemItems[i].ItemDataPoints = new PointF[this.ChartLineItems.Count];
                this.ChartItemItems[i].ItemDataRectF = new RectangleF[this.ChartLineItems.Count];

                float sum = this.ChartLoopItems.Count * this.LoopInterval;
                int datalen = this.ChartItemItems[i].ItemDataCurrent.Count();
                int linelen = this.ChartLineItems.Count;
                for (int j = 0; j < linelen; j++)
                {
                    PointF pointf = chart_center;
                    if (j < datalen)
                    {
                        pointf = CalculatePointForAngle(chart_center, this.ChartLineItems[j].LoopRadius * this.ChartItemItems[i].ItemDataCurrent[j] / sum, this.ChartLineItems[j].LineAngle);
                    }
                    this.ChartItemItems[i].ItemDataPoints[j] = pointf;
                    this.ChartItemItems[i].ItemDataRectF[j] = new RectangleF(this.ChartItemItems[i].ItemDataPoints[j].X - 2, this.ChartItemItems[i].ItemDataPoints[j].Y - 2, 4, 4);
                }
            }
            #endregion

        }

        /// <summary>
        /// 计算角度
        /// </summary>
        /// <param name="center">圆心坐标</param>
        /// <param name="radius">圆半径</param>
        /// <param name="angle">角度</param>
        /// <returns></returns>
        private static PointF CalculatePointForAngle(PointF center, float radius, float angle)
        {
            if (radius == 0)
                return center;

            float w = 0;
            float h = 0;
            if (angle <= 90)
            {
                w = radius * (float)Math.Cos(Math.PI / 180 * angle);
                h = radius * (float)Math.Sin(Math.PI / 180 * angle);
            }
            else if (angle <= 180)
            {
                w = -radius * (float)Math.Sin(Math.PI / 180 * (angle - 90));
                h = radius * (float)Math.Cos(Math.PI / 180 * (angle - 90));

            }
            else if (angle <= 270)
            {
                w = -radius * (float)Math.Cos(Math.PI / 180 * (angle - 180));
                h = -radius * (float)Math.Sin(Math.PI / 180 * (angle - 180));
            }
            else
            {
                w = radius * (float)Math.Sin(Math.PI / 180 * (angle - 270));
                h = -radius * (float)Math.Cos(Math.PI / 180 * (angle - 270));

            }
            return new PointF(center.X + w, center.Y + h);
        }

        /// <summary>
        /// 创建动画对象
        /// </summary>
        private void CreateAnimation()
        {
            this.animationTimer = new AnimationTimer(this, new AnimationOptions());
            this.animationTimer.AT = AnimationType.EaseBoth;
            this.animationTimer.Interval = 50;
            this.animationTimer.Options.AllTime = 500;
            this.animationTimer.Options.ForEverTimer = false;
            this.animationTimer.AnimationIng += new AnimationTimer.AnimationHandel(this.animationTimer_AnimationIng);
        }

        /// <summary>
        /// 动画进行中
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        protected void animationTimer_AnimationIng(object sender, AnimationEventArgs e)
        {
            #region 数据
            PointF chart_center = new PointF(this.ChartMainRect.ChartRect.X + this.ChartMainRect.ChartRect.Width / 2, this.ChartMainRect.ChartRect.Y + this.ChartMainRect.ChartRect.Height / 2);
            for (int i = 0; i < this.ChartItemItems.Count; i++)
            {
                this.ChartItemItems[i].ItemDataPoints = new PointF[this.ChartLineItems.Count];
                this.ChartItemItems[i].ItemDataRectF = new RectangleF[this.ChartLineItems.Count];

                float sum = this.ChartLoopItems.Count * this.LoopInterval;
                int datalen = this.ChartItemItems[i].ItemDataCurrent.Count();
                int linelen = this.ChartLineItems.Count;
                for (int j = 0; j < linelen; j++)
                {
                    float value = (float)(this.ChartItemItems[i].ItemDataCurrent[j] + (this.ChartItemItems[i].ItemDataTargrt[j] - this.ChartItemItems[i].ItemDataBefore[j]) * e.progressTime);
                    PointF pointf = chart_center;
                    if (j < datalen)
                    {
                        pointf = CalculatePointForAngle(chart_center, this.ChartLineItems[j].LoopRadius * value / sum, this.ChartLineItems[j].LineAngle);
                    }
                    this.ChartItemItems[i].ItemDataCurrent[j] = value;
                    this.ChartItemItems[i].ItemDataPoints[j] = pointf;
                    this.ChartItemItems[i].ItemDataRectF[j] = new RectangleF(this.ChartItemItems[i].ItemDataPoints[j].X - 2, this.ChartItemItems[i].ItemDataPoints[j].Y - 2, 4, 4);
                }
            }
            #endregion
            this.Invalidate();

        }

        #endregion

        /// <summary>
        /// 分析图环形配置集合
        /// </summary>
        [Description("分析图环形配置集合")]
        [Editor(typeof(CollectionEditorExt), typeof(UITypeEditor))]
        public sealed class ChartLoopCollection : IList, ICollection, IEnumerable
        {
            private ArrayList groupParamList = new ArrayList();
            private RadarChartExt owner;

            public ChartLoopCollection(RadarChartExt owner)
            {
                this.owner = owner;
            }

            #region IEnumerable

            public IEnumerator GetEnumerator()
            {
                ChartLoop[] listArray = new ChartLoop[this.groupParamList.Count];
                for (int index = 0; index < listArray.Length; ++index)
                    listArray[index] = (ChartLoop)this.groupParamList[index];
                return listArray.GetEnumerator();
            }

            #endregion

            #region ICollection

            public void CopyTo(Array array, int index)
            {
                for (int i = 0; i < this.Count; i++)
                    array.SetValue(this.groupParamList[i], i + index);
            }

            public int Count
            {
                get
                {
                    return this.groupParamList.Count;
                }
            }

            public bool IsSynchronized
            {
                get
                {
                    return false;
                }
            }

            public object SyncRoot
            {
                get
                {
                    return (object)this;
                }
            }

            #endregion

            #region IList

            public int Add(ChartLoop value)
            {
                this.groupParamList.Add(value);
                this.owner.InitializeRectangle();
                this.owner.Invalidate();
                return this.Count - 1;
            }

            public int Add(object value)
            {
                ChartLoop groupParam = (ChartLoop)value;
                this.groupParamList.Add(groupParam);
                this.owner.InitializeRectangle();
                this.owner.Invalidate();
                return this.Count - 1;
            }

            public void Clear()
            {
                this.groupParamList.Clear();
                this.owner.InitializeRectangle();
                this.owner.Invalidate();
            }

            public bool Contains(object value)
            {
                return this.IndexOf(value) != -1;
            }

            public int IndexOf(object value)
            {
                return this.groupParamList.IndexOf(value);
            }

            public void Insert(int index, object value)
            {
                throw new NotImplementedException();
            }

            public bool IsFixedSize
            {
                get { return false; }
            }

            public bool IsReadOnly
            {
                get { return false; }
            }

            public void Remove(object value)
            {
                if (!(value is ChartLoop))
                    return;
                this.groupParamList.Remove((ChartLoop)value);
                this.owner.InitializeRectangle();
                this.owner.Invalidate();
            }

            public void RemoveAt(int index)
            {
                this.groupParamList.RemoveAt(index);
                this.owner.InitializeRectangle();
                this.owner.Invalidate();
            }

            public ChartLoop this[int index]
            {
                get
                {
                    if (index >= this.Count)
                        return null;
                    return (ChartLoop)this.groupParamList[index];
                }
                set
                {
                    this.groupParamList[index] = (ChartLoop)value;
                    this.owner.InitializeRectangle();
                    this.owner.Invalidate();
                }
            }

            object IList.this[int index]
            {
                get
                {
                    return (object)this.groupParamList[index];
                }
                set
                {
                    this.groupParamList[index] = (ChartLoop)value;
                    this.owner.InitializeRectangle();
                    this.owner.Invalidate();
                }
            }

            #endregion

        }

        /// <summary>
        /// 分析图角度线配置集合
        /// </summary>
        [Description("分析图角度线配置集合")]
        [Editor(typeof(CollectionEditorExt), typeof(UITypeEditor))]
        public sealed class ChartLineCollection : IList, ICollection, IEnumerable
        {
            private ArrayList groupParamList = new ArrayList();
            private RadarChartExt owner;

            public ChartLineCollection(RadarChartExt owner)
            {
                this.owner = owner;
            }

            #region IEnumerable

            public IEnumerator GetEnumerator()
            {
                ChartLine[] listArray = new ChartLine[this.groupParamList.Count];
                for (int index = 0; index < listArray.Length; ++index)
                    listArray[index] = (ChartLine)this.groupParamList[index];
                return listArray.GetEnumerator();
            }

            #endregion

            #region ICollection

            public void CopyTo(Array array, int index)
            {
                for (int i = 0; i < this.Count; i++)
                    array.SetValue(this.groupParamList[i], i + index);
            }

            public int Count
            {
                get
                {
                    return this.groupParamList.Count;
                }
            }

            public bool IsSynchronized
            {
                get
                {
                    return false;
                }
            }

            public object SyncRoot
            {
                get
                {
                    return (object)this;
                }
            }

            #endregion

            #region IList


            public int Add(ChartLine value)
            {
                this.groupParamList.Add(value);
                this.owner.InitializeRectangle();
                this.owner.Invalidate();
                return this.Count - 1;
            }
            public int Add(object value)
            {
                ChartLine groupParam = (ChartLine)value;
                this.groupParamList.Add(groupParam);
                this.owner.InitializeRectangle();
                this.owner.Invalidate();
                return this.Count - 1;
            }

            public void Clear()
            {
                this.groupParamList.Clear();
                this.owner.InitializeRectangle();
                this.owner.Invalidate();
            }

            public bool Contains(object value)
            {
                return this.IndexOf(value) != -1;
            }

            public int IndexOf(object value)
            {
                return this.groupParamList.IndexOf(value);
            }

            public void Insert(int index, object value)
            {
                throw new NotImplementedException();
            }

            public bool IsFixedSize
            {
                get { return false; }
            }

            public bool IsReadOnly
            {
                get { return false; }
            }

            public void Remove(object value)
            {
                if (!(value is ChartLine))
                    return;
                this.groupParamList.Remove((ChartLine)value);
                this.owner.InitializeRectangle();
                this.owner.Invalidate();
            }

            public void RemoveAt(int index)
            {
                this.groupParamList.RemoveAt(index);
                this.owner.InitializeRectangle();
                this.owner.Invalidate();
            }

            public ChartLine this[int index]
            {
                get
                {
                    if (index >= this.Count)
                        return null;
                    return (ChartLine)this.groupParamList[index];
                }
                set
                {
                    this.groupParamList[index] = (ChartLine)value;
                    this.owner.InitializeRectangle();
                    this.owner.Invalidate();
                }
            }

            object IList.this[int index]
            {
                get
                {
                    return (object)this.groupParamList[index];
                }
                set
                {
                    this.groupParamList[index] = (ChartLine)value;
                    this.owner.InitializeRectangle();
                    this.owner.Invalidate();
                }
            }

            #endregion

        }

        /// <summary>
        /// 分析图选项数据集合
        /// </summary>
        [Description("分析图选项数据集合")]
        [Editor(typeof(CollectionEditorExt), typeof(UITypeEditor))]
        public sealed class ChartItemCollection : IList, ICollection, IEnumerable
        {
            private ArrayList groupParamList = new ArrayList();
            private RadarChartExt owner;

            public ChartItemCollection(RadarChartExt owner)
            {
                this.owner = owner;
            }

            #region IEnumerable

            public IEnumerator GetEnumerator()
            {
                ChartItem[] listArray = new ChartItem[this.groupParamList.Count];
                for (int index = 0; index < listArray.Length; ++index)
                    listArray[index] = (ChartItem)this.groupParamList[index];
                return listArray.GetEnumerator();
            }

            #endregion

            #region ICollection

            public void CopyTo(Array array, int index)
            {
                for (int i = 0; i < this.Count; i++)
                    array.SetValue(this.groupParamList[i], i + index);
            }

            public int Count
            {
                get
                {
                    return this.groupParamList.Count;
                }
            }

            public bool IsSynchronized
            {
                get
                {
                    return false;
                }
            }

            public object SyncRoot
            {
                get
                {
                    return (object)this;
                }
            }

            #endregion

            #region IList

            public int Add(ChartItem value)
            {
                this.groupParamList.Add(value);
                return this.Count - 1;
            }

            public int Add(object value)
            {
                ChartItem groupParam = (ChartItem)value;
                this.groupParamList.Add(groupParam);
                return this.Count - 1;
            }
            public void Clear()
            {
                this.groupParamList.Clear();
            }

            public bool Contains(object value)
            {
                return this.IndexOf(value) != -1;
            }

            public int IndexOf(object value)
            {
                return this.groupParamList.IndexOf(value);
            }

            public void Insert(int index, object value)
            {
                throw new NotImplementedException();
            }

            public bool IsFixedSize
            {
                get { return false; }
            }

            public bool IsReadOnly
            {
                get { return false; }
            }

            public void Remove(object value)
            {
                if (!(value is ChartItem))
                    return;
                this.groupParamList.Remove((ChartItem)value);
            }

            public void RemoveAt(int index)
            {
                this.groupParamList.RemoveAt(index);
            }

            public ChartItem this[int index]
            {
                get
                {
                    return (ChartItem)this.groupParamList[index];
                }
                set
                {
                    this.groupParamList[index] = (ChartItem)value;
                }
            }

            object IList.this[int index]
            {
                get
                {
                    return (object)this.groupParamList[index];
                }
                set
                {
                    this.groupParamList[index] = (ChartItem)value;
                }
            }

            #endregion

        }
    }

 

源码下载:雷达分析图控件.zip

以上是关于雷达分析图控件----------WinForm控件开发系列的主要内容,如果未能解决你的问题,请参考以下文章

(七十二)c#Winform自定义控件-雷达图

C#WinForm程序树形表显示

wpf怎么使用WindowsFormsHost(即winform控件)

Winform自定义控件:ImageButton(转)

winform VS2010视图设计器更新的问题

WinForm------GridControl控件中使用SearchLookUpEdit控件的方法