C# 报表设计器 (winform 设计端)开发与实现生成网页的HTML报表 开放源码及调试

Posted szzzzn

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了C# 报表设计器 (winform 设计端)开发与实现生成网页的HTML报表 开放源码及调试相关的知识,希望对你有一定的参考价值。

记得2010年之前,公司的项目基本上都要用到报表,以前我们常用的方法就是针对客户的需求来定制化开发(基本上是死写代码)来实现,经常导致项目经常性的延期,因为客户的需求经常会变化,随着用户的使用认知度的提高,对报表的要求越来越高,导致程序员不停的修改代码来实现,效率不高、结束遥遥无期。。。非常的痛苦;当然市面上有很多报表开发工具可以实现,但是针对小公司来说采购一套这样的系统的成本也非常的高,所以我们决定自己来开发一套像目前的润乾、FineReport 这样的报表设计器,来实现快速的报表设计制作。

当初为了开发这样的系统,花费的了很长的时间学习查阅各种资料,其痛苦只有程序员才能体会,因为没有任何现成的实例代码可供参考,只有看别人的思路来一步步的摸索,本文将我们当初设计制作的报表设计器的功能分享出来,让有需要的或想开发报表设计的朋友们提供一个参考,尽量少走很动弯路,设计端可以直接使用,但是计算引擎和网页的计算的源码就不能分享出来了(请不要介意,因为涉及到公司的保密原因)

记得当初为了制作报表设计器,在网上查找有没有相关的实例资料,找了很久,也是没有找到合适的,后来发现 SourceGrid 可以实现单元格的合并拆分功能,所以决定修改实现winform端的报表设计。下面我将制作的E_Report 报表控件抽取出来建立一个简易的Winform的可运行的实例提供给大伙下载,希望能给你的开发提供一点帮助和借鉴;当然你可以直接使用也可以,里面的设计功能基本全部能。

抽取出来的源码包含:E_Report 报表设计自定义控件DLL源码; EReportDemo 建立的简易Winform 端设计器使用DLL的实例源码;

报表设计器实例完整源码下载地址:www.sdpsoft.com/==》下载中心==》报表设计器简易源码----自定义报表控件(源码)以及在Winform中的使用源码

或直接下载地址:winform报表设计工具源码

一、运行效果

实例中,只做了一个简单的效果,工具栏的按钮在单元格右击属性中都有,只是放了几个常用的在工具导航栏中(右击单元格属性可以看到设计导航)

可以进行单元格的合并、拆分、字体、颜色、背景、边框等的设置,朋友们可以自己编写保存发布等功能,实现报表的真实功能;

例如单元格属性(其他还有很多的属性,自己下载源码后运行起来就能看到了)

对表格的斜线、斜线文字有很好的支持;可以设置表头、表位、标题等 实际效果图如下

二、使用介绍

1、页面初始化的时候,通过 ReportDoc 类 初始报表的行列及单元格属性

using System;
using System.Collections.Generic;
using System.Text;
using System.Drawing;
using System.Windows.Forms;
using System.Drawing.Drawing2D;
using System.Xml;
using System.Collections;
using E_Report;

namespace EReportDemo

    /// <summary>
    /// 报表表格对象
    /// </summary>
    public class ReportDoc
    
        #region 变量参数定义

        /// <summary>
        /// 表格对象
        /// </summary>
        private EReport _nowReport;

        /// <summary>
        /// 报表配置编码
        /// </summary>
        private string _reportCode = "";

        /// <summary>
        /// 表报设计状态
        /// </summary>
        private string _reportState = "";

        #endregion

        #region 函数构造方法

        /// <summary>
        /// 构造函数
        /// </summary>
        public ReportDoc()
        
            this._nowReport = null;
            this._reportCode = "";
            this._reportState = "";

        


        /// <summary>
        /// 获取--设置--表格对象
        /// </summary>
        public EReport NowReport
        
            get  return this._nowReport; 
            set  this._nowReport = value; 
        

        /// <summary>
        /// 报表配置编码
        /// </summary>
        public string ReportCode
        
            get  return this._reportCode; 
            set  this._reportCode = value; 
        

        /// <summary>
        /// 报表设计状态
        /// 新增、修改 两种状态
        /// </summary>
        public string ReportState
        
            get  return this._reportState; 
            set  this._reportState = value; 
        

        /// <summary>
        /// 资源释放
        /// </summary>
        ~ReportDoc()
        
            this._nowReport = null;
            this._reportState = "";

        

        #endregion

        #region 加载报表表格

        /// <summary>
        /// 初始化--报表表格
        /// </summary>
        public void InitReport()
        

            int rCount = 41;  // 41行
            int cCount = 20;  // 20列

            _nowReport.Redim(rCount, cCount);
            _nowReport.FixedRows = 1;
            _nowReport.FixedColumns = 1;

            InitCells();

        

        /// <summary>
        /// 初始化--单元格
        /// </summary>
        public void InitCells()
        
            // 第一行 第一列
            _nowReport.Rows[0].Height = 23;
            _nowReport.Columns[0].Width = 50;

            // 设置00格
            _nowReport[0, 0] = new E_Report.Cells.HeaderColumn("");

            //  设置行
            for (int rr = 1; rr < _nowReport.RowsCount; rr++)
            
                string tmRowT = rr.ToString();
                _nowReport[rr, 0] = new E_Report.Cells.HeaderRow(tmRowT);
            

            //  设置列
            for (int cc = 1; cc < _nowReport.ColumnsCount; cc++)
            
                _nowReport[0, cc] = new E_Report.Cells.HeaderColumn(_nowReport.GetColumnHeadTileChar(cc));
            

            // 设置单元格
            for (int iRow = 1; iRow < _nowReport.RowsCount; iRow++)
            
                for (int iCol = 1; iCol < _nowReport.ColumnsCount; iCol++)
                
                    _nowReport[iRow, iCol] = new E_Report.Cells.Cell("", typeof(string));
                
            

        


        #endregion

    

2、工具导航栏 设置单元格相关属性

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using System.Collections;
using E_Report;

namespace EReportDemo

    /// <summary>
    /// 本程序只是Winform端的报表设计功能
    /// 至于其他的功能,本实例没有提供
    /// 报表设计的设计效果:可以查看  www.sdpsoft.com  SDP软件快速开发平台 报表设计篇
    /// </summary>

    public partial class EReportMain : Form
    
        private ReportDoc report;
        private E_Report.Cells.Controllers.PopupMenu myPopupMenu;

        public EReportMain()
        
            InitializeComponent();
        

        private void EReportMain_Load(object sender, EventArgs e)
        
            Cursor.Current = Cursors.WaitCursor;
            gridMain.Rows.Clear();
            myPopupMenu = new E_Report.Cells.Controllers.PopupMenu(gridMain);

            report = new ReportDoc();
            report.NowReport = gridMain;
            report.InitReport();
            Cursor.Current = Cursors.Default;
        

        private void gridMain_MouseMove(object sender, MouseEventArgs e)
        
            this.lbl_X.Text = e.X.ToString();
            this.lbl_Y.Text = e.Y.ToString();
        

        /// <summary>
        /// 工具栏报表单元格事件
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void btn_GridTools_Click(object sender, EventArgs e)
        
            string sType = ((Button)sender).Tag.ToString().Trim().ToLower();
            switch (sType)
            

                case "cellproperty":  // 单元格属性设置
                    myPopupMenu.CellProperty_Click(sender, e);
                    break;
                case "fontset":       // 单元格字体设置
                    myPopupMenu.CellFont_Click(sender, e);
                    break;
                case "fontcolor":     // 文本字体颜色
                    myPopupMenu.CellForColor_Click(sender, e);
                    break;
                case "backcolor":     // 单元格背景色
                    myPopupMenu.CellBackColor_Click(sender, e);
                    break;
                case "cellborder":   // 单元格边框设置
                    myPopupMenu.CellBorder_Click(sender, e);
                    break;
                case "lock":         // 设置表格只读
                    myPopupMenu.LockReport_Click(sender, e);
                    break;
                case "unlock":       // 设置表格编辑
                    myPopupMenu.UnLockReport_Click(sender, e);
                    break;
                case "alignleft":    // 水平居左对齐
                    myPopupMenu.AlignLeft_Click(sender, e);
                    break;
                case "aligncenter":  // 水平居中对齐
                    myPopupMenu.AlignCenter_Click(sender, e);
                    break;
                case "alignright":   // 水平居右对齐
                    myPopupMenu.AlignRight_Click(sender, e);
                    break;
                case "aligntop":     // 垂直居上对齐
                    myPopupMenu.AlignTop_Click(sender, e);
                    break;
                case "alignmiddle":  // 垂直居中对齐
                    myPopupMenu.AlignMiddle_Click(sender, e);
                    break;
                case "alignbottom":  // 垂直居下对齐
                    myPopupMenu.AlignBottom_Click(sender, e);
                    break;
                case "addindent":    // 增加文本缩进
                    myPopupMenu.AddIndent_Click(sender, e);
                    break;
                case "delindent":    // 清除文本缩进
                    myPopupMenu.RemoveIndent_Click(sender, e);
                    break;
                case "insertrow":    // 插入后一行
                    myPopupMenu.InsertRow_Click(sender, e);
                    break;
                case "appendrow":    // 表格追加行
                    myPopupMenu.AddRow_Click(sender, e);
                    break;
                case "delrow":       // 删除选中行
                    myPopupMenu.DeleteRows_Click(sender, e);
                    break;
                case "hiderow":      // 隐藏选中行
                    myPopupMenu.HideSelectRows_Click(sender, e);
                    break;
                case "showrow":      // 显示选中行
                    myPopupMenu.ShowSelectRows_Click(sender, e);
                    break;
                case "showallrow":   // 显示所有行
                    myPopupMenu.ShowAllRows_Click(sender, e);
                    break;
                case "insertcol":    // 插入左侧列
                    myPopupMenu.InsertColumn_Click(sender, e);
                    break;
                case "addcol":       // 插入右侧列
                    myPopupMenu.AddColumn_Click(sender, e);
                    break;
                case "delcol":       // 删除选中列
                    myPopupMenu.DeleteColumns_Click(sender, e);
                    break;
                case "hidecol":      // 隐藏选中列
                    myPopupMenu.HideSelectColumns_Click(sender, e);
                    break;
                case "showcol":      // 显示选中列
                    myPopupMenu.ShowSelectColumns_Click(sender, e);
                    break;
                case "showallcol":   // 显示所有列
                    myPopupMenu.ShowAllColumns_Click(sender, e);
                    break;
                case "mergecell":    // 合并单元格
                    myPopupMenu.MergeCell_Click(sender, e);
                    break;
                case "splitcell":    // 拆分单元格
                    myPopupMenu.SplitCell_Click(sender, e);
                    break;
            
        
    

3、报表控件DLL类库部分

里面有我们自定义的 条码控件、图片控件、图表控件


表格内自定义图表控件(曲线、柱状、饼状)源码

using System;
using System.Collections.Generic;
using System.Text;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Drawing.Text;

namespace E_Report

    /// <summary>
    /// 图表属性
    /// </summary>
    /// <summary>
    /// 报表图表类库
    /// </summary>
    public class EChart
    
        #region 属性方法

        #region 临时变量

        /// <summary>
        /// 临时变量--关联单元格行号
        /// </summary>
        private int _row = 0;

        /// <summary>
        /// 获取--设置--关联单元格行号
        /// </summary>
        public int Row
        
            get  return _row; 
            set  _row = value; 
        

        /// <summary>
        /// 临时变量--关联单元格列号
        /// </summary>
        private int _col = 0;

        /// <summary>
        /// 获取--设置--关联单元格列号
        /// </summary>
        public int Col
        
            get  return _col; 
            set  _col = value; 
        

        /// <summary>
        /// 数据来源
        /// </summary>
        private string _t_DataFrom = "数据源";

        /// <summary>
        /// 获取--设置--数据来源
        /// </summary>
        public string T_DataFrom
        
            get  return _t_DataFrom; 
            set  _t_DataFrom = value; 
        

        /// <summary>
        /// 数据源名称
        /// </summary>
        private string _t_DsName = "";

        /// <summary>
        /// 获取--设置--数据源名称
        /// </summary>
        public string T_DsName
        
            get  return _t_DsName; 
            set  _t_DsName = value; 
        

        /// <summary>
        /// 项目名称
        /// </summary>
        private string _t_ItemName = "";

        /// <summary>
        /// 获取--设置--项目名称
        /// </summary>
        public string T_ItemName
        
            get  return _t_ItemName; 
            set  _t_ItemName = value; 
        

        /// <summary>
        /// 项目数值
        /// </summary>
        private string _t_ItemValue = "";

        /// <summary>
        /// 获取--设置--项目数值
        /// </summary>
        public string T_ItemValue
        
            get  return _t_ItemValue; 
            set  _t_ItemValue = value; 
        

        /// <summary>
        /// X轴刻度
        /// </summary>
        private string _t_XScale = "";

        /// <summary>
        /// 获取--设置--X轴刻度
        /// </summary>
        public string T_XScale
        
            get  return _t_XScale; 
            set  _t_XScale = value; 
        


        #endregion

        #region 图表属性

        /// <summary>
        /// 图表名称ID
        /// </summary>
        private string _name = "";

        /// <summary>
        /// 获取--设置--图表名称ID
        /// </summary>
        public string Name
        
            get  return _name; 
            set  _name = value; 
        

        /// <summary>
        /// 图表类型
        /// </summary>
        private EChartType _chartType = EChartType.Curve;

        /// <summary>
        /// 获取--设置--图表类型
        /// 默认:Line 折曲线
        /// </summary>
        public EChartType ChartType
        
            get  return _chartType; 
            set  _chartType = value; 
        

        /// <summary>
        /// 图表宽度
        /// </summary>
        private int _chartWidth = 0;

        /// <summary>
        /// 获取--设置--图表宽度
        /// </summary>
        public int ChartWidth
        
            get  return _chartWidth; 
            set  _chartWidth = value; 
        

        /// <summary>
        /// 图表高度
        /// </summary>
        private int _chartHeight = 0;

        /// <summary>
        /// 获取--设置--图表高度
        /// </summary>
        public int ChartHeight
        
            get  return _chartHeight; 
            set  _chartHeight = value; 
        

        /// <summary>
        /// 图表背景颜色
        /// </summary>
        private Color _backColor = Color.White;

        /// <summary>
        /// 获取--设置--图表背景颜色
        /// </summary>
        public Color BackColor
        
            get  return _backColor; 
            set  _backColor = value; 
        

        /// <summary>
        /// 是否显示图表边框
        /// </summary>
        private bool _showBorder = true;

        /// <summary>
        /// 获取--设置--是否显示图表边框
        /// 默认:true 显示
        /// </summary>
        public bool ShowBorder
        
            get  return _showBorder; 
            set  _showBorder = value; 
        

        /// <summary>
        /// 图表边框颜色
        /// </summary>
        private Color _borderColor = Color.LightGray;

        /// <summary>
        /// 获取--设置--图表边框颜色
        /// </summary>
        public Color BorderColor
        
            get  return _borderColor; 
            set  _borderColor = value; 
        

        /// <summary>
        /// 是否显示网格线
        /// </summary>
        private bool _showGrid = true;

        /// <summary>
        /// 获取--设置--是否显示网格线
        /// 默认:true 显示
        /// </summary>
        public bool ShowGrid
        
            get  return _showGrid; 
            set  _showGrid = value; 
        

        /// <summary>
        /// 线条张力系数
        /// </summary>
        private float _lineTension = 0.3f;

        /// <summary>
        /// 获取--设置--线条张力系数
        /// 默认:0.3
        /// </summary>
        public float LineTension
        
            get  return _lineTension; 
            set
            
                if (value < 0.0f && value > 1.0f)
                    _lineTension = 0.5f;
                else
                    _lineTension = value;
            
        

        #endregion

        #region 标题属性

        /// <summary>
        /// 是否显示主标题
        /// </summary>
        private bool _showTitle = true;

        /// <summary>
        /// 获取--设置--是否显示主标题
        /// 默认:true 显示
        /// </summary>
        public bool ShowTitle
        
            get  return _showTitle; 
            set  _showTitle = value; 
        

        /// <summary>
        /// 主标题文本
        /// </summary>
        private string _title = "";

        /// <summary>
        /// 获取--设置--主标题文本
        /// </summary>
        public string Title
        
            get  return _title; 
            set  _title = value; 
        

        /// <summary>
        /// 主标题字体
        /// </summary>
        private Font _titleFont = new Font("黑体", 12);

        /// <summary>
        /// 获取--设置--主标题字体
        /// </summary>
        public Font TitleFont
        
            get  return _titleFont; 
            set  _titleFont = value; 
        

        /// <summary>
        /// 主标题颜色
        /// </summary>
        private Color _titleColor = Color.Black;

        /// <summary>
        /// 获取--设置--主标题颜色
        /// </summary>
        public Color TitleColor
        
            get  return _titleColor; 
            set  _titleColor = value; 
        

        /// <summary>
        /// 主标题对齐方式
        /// </summary>
        private EAlign _titleAlign = EAlign.center;

        /// <summary>
        /// 获取--设置--主标题对齐方式
        /// </summary>
        public EAlign TitleAlign
        
            get  return _titleAlign; 
            set  _titleAlign = value; 
        

        /// <summary>
        /// 是否显示副标题
        /// </summary>
        private bool _showSubTilte = true;

        /// <summary>
        /// 获取--设置--是否显示副标题
        /// 默认:true 显示
        /// </summary>
        public bool ShowSubTitle
        
            get  return _showSubTilte; 
            set  _showSubTilte = value; 
        

        /// <summary>
        /// 副标题文本
        /// </summary>
        private string _subTitle = "";

        /// <summary>
        /// 获取--设置--副标题文本
        /// </summary>
        public string SubTitle
        
            get  return _subTitle; 
            set  _subTitle = value; 
        

        /// <summary>
        /// 副标题字体
        /// </summary>
        private Font _subTitleFont = new Font("黑体", 10);

        /// <summary>
        /// 获取--设置--副标题字体
        /// </summary>
        public Font SubTitleFont
        
            get  return _subTitleFont; 
            set  _subTitleFont = value; 
        

        /// <summary>
        /// 副标题颜色
        /// </summary>
        private Color _subTitleColor = Color.Blue;

        /// <summary>
        /// 获取--设置--副标题颜色
        /// </summary>
        public Color SubTitleColor
        
            get  return _subTitleColor; 
            set  _subTitleColor = value; 
        

        /// <summary>
        /// 副标题对齐方式
        /// </summary>
        private EAlign _subTitleAlign = EAlign.center;

        /// <summary>
        /// 获取--设置--副标题对齐方式
        /// </summary>
        public EAlign SubTitleAlign
        
            get  return _subTitleAlign; 
            set  _subTitleAlign = value; 
        

        /// <summary>
        /// 副标题水平方向偏移量
        /// + - 整数
        /// </summary>
        private int _subTitleOffset = 0;

        /// <summary>
        /// 获取--设置--副标题水平方向偏移量
        /// </summary>
        public int SubTitleOffset
        
            get  return _subTitleOffset; 
            set  _subTitleOffset = value; 
        

        #endregion

        #region 图例属性

        /// <summary>
        /// 是否显示图例
        /// </summary>
        private bool _showLegend = true;

        /// <summary>
        /// 是否显示图例
        /// </summary>
        public bool ShowLegend
        
            get  return _showLegend; 
            set  _showLegend = value; 
        

        /// <summary>
        /// 图例字体
        /// </summary>
        private Font _legendFont = new Font("宋体", 9);

        /// <summary>
        /// 获取--设置--图例字体
        /// </summary>
        public Font LegendFont
        
            get  return _legendFont; 
            set  _legendFont = value; 
        

        /// <summary>
        /// 图例字体颜色
        /// </summary>
        private Color _legendColor = Color.Black;

        /// <summary>
        /// 获取--设置--图例字体颜色
        /// </summary>
        public Color LegendColor
        
            get  return _legendColor; 
            set  _legendColor = value; 
        

        /// <summary>
        /// 图例对齐方式
        /// </summary>
        private EAlign _legendAlign = EAlign.center;

        /// <summary>
        /// 获取--设置--图例对齐方式
        /// </summary>
        public EAlign LegendAlign
        
            get  return _legendAlign; 
            set  _legendAlign = value; 
        

        #endregion

        #region 坐标属性

        /// <summary>
        /// 获取--X轴分割段数
        /// </summary>
        public int XSplitNum
        
            get  return _xScaleValues.Count; 
        

        /// <summary>
        /// Y轴分割段数
        /// </summary>
        private int _ySplitNum = 5;

        /// <summary>
        /// 获取--设置--分割段数
        /// 默认:5
        /// 范围:最小5
        /// </summary>
        public int YSplitNum
        
            get  return _ySplitNum; 
            set
            
                if (value < 5)
                    _ySplitNum = 5;
                else
                    _ySplitNum = value;

            
        

        /// <summary>
        /// X 轴标
        /// </summary>
        private string _xAxisText = "";

        /// <summary>
        /// 获取--设置--X 轴标
        /// </summary>
        public string XAxisText
        
            get  return _xAxisText; 
            set  _xAxisText = value; 
        

        /// <summary>
        /// Y 轴标
        /// </summary>
        private string _yAxisText = "";

        /// <summary>
        /// 获取--设置--Y 轴标
        /// </summary>
        public string YAxisText
        
            get  return _yAxisText; 
            set  _yAxisText = value; 
        

        /// <summary>
        /// X轴文本旋转角度
        /// 默认:0
        /// 范围:0~90
        /// </summary>
        private float _xRotateAngle = 0.0f;

        /// <summary>
        /// 获取--设置--X轴文本旋转角度
        /// </summary>
        public float XRotateAngle
        
            get  return _xRotateAngle; 
            set
            
                if (value >= 0.0f && value <= 90.0f)
                    _xRotateAngle = value;
                else
                    _xRotateAngle = 0.0f;
            
        

        #endregion

        #region 绘图变量

        /// <summary>
        /// 绘图对象
        /// </summary>
        private Graphics g = null;

        /// <summary>
        /// 图表颜色数组
        /// </summary>
        private static Color[] ChartColor =  
                                                 Color.Red, Color.Blue, Color.Orange, Color.Green, Color.Cyan, Color.Purple,
                                                 Color.Coral, Color.Chocolate, Color.Gray, Color.Gold, Color.Lavender, Color.Linen,
                                                 Color.Magenta, Color.Moccasin, Color.Navy, Color.Olive, Color.Peru, Color.Plum,
                                                 Color.Purple, Color.Salmon, Color.Sienna, Color.Silver, Color.Tan, Color.Tomato, 
                                                 Color.Violet, Color.Turquoise, Color.Transparent
                                             ;

        /// <summary>
        /// 边距10px
        /// </summary>
        private float Margin = 10;

        /// <summary>
        /// 起点 X 坐标
        /// </summary>
        private float Start_X = 0;

        /// <summary>
        /// 起点 Y 坐标
        /// </summary>
        private float Start_Y = 0;

        /// <summary>
        /// 终点 X 坐标
        /// </summary>
        private float End_X = 0;

        /// <summary>
        /// 终点 Y 坐标
        /// </summary>
        private float End_Y = 0;

        /// <summary>
        /// X轴刻度宽度
        /// </summary>
        private float XScaleWidth = 0;

        /// <summary>
        /// Y轴刻度宽度
        /// </summary>
        private float YScaleWidth = 0;

        /// <summary>
        /// Y轴刻度间隔值
        /// 说明:Y轴坐标全部采用整数,表示每个间隔的计算单位值
        /// 包含正负数
        /// </summary>
        private double YScale_SplitValue = 0;

        /// <summary>
        /// Y轴刻度开始值
        /// </summary>
        private double YScale_StartValue = 0;

        /// <summary>
        /// 坐标轴原点坐标
        /// </summary>
        private PointF AxisZeroPt = new PointF(0f, 0f);

        /// <summary>
        /// 图表数据
        /// </summary>
        private string _chartData = "";

        /// <summary>
        /// 获取--设置--图表数据
        /// </summary>
        public string ChartData
        
            get  return _chartData; 
            set  _chartData = value; 
        

        /// <summary>
        /// 绘图笔刷
        /// </summary>
        private Brush brush;

        /// <summary>
        /// 绘制画笔
        /// </summary>
        private Pen pen;

        /// <summary>
        /// 绘图矩形
        /// </summary>
        private RectangleF rectF = new RectangleF(0, 0, 0, 0);

        /// <summary>
        /// 字符格式化
        /// </summary>
        private StringFormat stringFormat;

        /// <summary>
        /// 临时变量 最大值
        /// </summary>
        private double myMaxValue = 0;

        /// <summary>
        /// 临时变量 最小值
        /// </summary>
        private double myMinValue = 0;

        /// <summary>
        /// 临时变量 X轴刻度最大高度
        /// 用于绘制坐标轴的时候进行偏移
        /// </summary>
        private float myXScaleMaxHeight = 0;

        /// <summary>
        /// 临时变量 Y轴刻度值字符串的最大宽度
        /// 用于绘制坐标轴的时候进行偏移
        /// </summary>
        private float myYScaleMaxWidth = 0;

        #endregion

        #region 图表数据

        /// <summary>
        /// X轴刻度值数组
        /// </summary>
        private List<string> _xScaleValues = new List<string>();

        /// <summary>
        /// 获取--设置--X轴刻度值数组
        /// </summary>
        public List<string> XScaleValues
        
            get  return _xScaleValues; 
            set  _xScaleValues = value; 
        

        /// <summary>
        /// 图表数据
        /// </summary>
        private List<EChartData> _chartDataArray = new List<EChartData>();

        /// <summary>
        /// 获取--设置--图表数据
        /// </summary>
        public List<EChartData> ChartDataArray
        
            get  return _chartDataArray; 
            set  _chartDataArray = value; 
        

        #endregion

        #endregion

        #region 构造方法

        /// <summary>
        /// 构造函数
        /// </summary>
        public EChart()
        

        

        /// <summary>
        /// 构造函数
        /// </summary>
        /// <param name="eChart"></param>
        public EChart(EChart eChart)
        

        

        #endregion

        #region 生成图表

        /// <summary>
        /// 生成图表
        /// </summary>
        /// <returns>返回:图表图像</returns>
        public Bitmap CreateImage()
        
            Bitmap ChartImage = new Bitmap(ChartWidth, ChartHeight);
            g = Graphics.FromImage(ChartImage);
            g.SmoothingMode = SmoothingMode.Default;
            g.TextRenderingHint = TextRenderingHint.ClearTypeGridFit;
            g.Clear(Color.White);

            Start_X = Margin;
            Start_Y = Margin;
            End_X = ChartWidth - Margin;
            End_Y = ChartHeight - Margin;

            DrawChart();

            g.Dispose();

            return ChartImage;
        

        #endregion

        #region 绘制方法

        /// <summary>
        /// 绘制图表
        /// </summary>
        private void DrawChart()
        
            DrawChart_InitGraph();
            DrawChart_MainTitle();
            DrawChart_SubTitle();
            DrawChart_Legend();
            DrawChart_YAxisText();
            if (ChartType != EChartType.Pie)
            
                DrawChart_Axis();
                if (ChartType == EChartType.Curve)
                    DrawChart_Curve();
                else
                    DrawChart_Bar();
            
            else
            
                DrawChart_Pie();
            
        

        /// <summary>
        /// 绘制图表--绘制背景图
        /// </summary>
        private void DrawChart_InitGraph()
        
            // 绘制图表外围边框
            if (_showBorder)
                g.DrawRectangle(new Pen(BorderColor, 1), 0, 0, (ChartWidth - 1), (ChartHeight - 1));

            // 填充图表背景颜色
            g.FillRectangle(new SolidBrush(BackColor), 1, 1, ChartWidth - 2, ChartHeight - 2);

        

        /// <summary>
        /// 绘制图表--绘制主标题
        /// </summary>
        private void DrawChart_MainTitle()
        
            if (ShowTitle)
            
                if (Title != null && Title.Trim() != "")
                
                    brush = new SolidBrush(TitleColor);                     // 矩形填充笔刷
                    SizeF sizeF = g.MeasureString(Title, TitleFont);        // 测试字体大小
                    stringFormat = new StringFormat();                      // 格式化字符串
                    stringFormat.LineAlignment = StringAlignment.Center;    // 垂直对齐方式
                    switch (TitleAlign)                                     // 水平对齐方式
                    
                        case EAlign.center:
                            stringFormat.Alignment = StringAlignment.Center;
                            break;
                        case EAlign.right:
                            stringFormat.Alignment = StringAlignment.Far;
                            break;
                        default:
                            stringFormat.Alignment = StringAlignment.Near;
                            break;
                    

                    rectF = new RectangleF(Start_X, Start_Y, (float)(ChartWidth - 4), sizeF.Height);  // 文字的矩形
                    g.DrawString(Title, TitleFont, brush, rectF, stringFormat);                       // 绘制主标题
                    Start_Y += sizeF.Height + 3f;                                                     // 设置Y起点值 + 3px
                
            
        

        /// <summary>
        /// 绘制图表--绘制副标题
        /// </summary>
        private void DrawChart_SubTitle()
        
            if (ShowSubTitle)
            
                if (SubTitle != null && SubTitle.Trim() != "")
                
                    brush = new SolidBrush(SubTitleColor);                  // 矩形填充笔刷
                    SizeF sizeF = g.MeasureString(SubTitle, SubTitleFont);  // 测试字体大小
                    stringFormat = new StringFormat();                      // 格式化字符串
                    stringFormat.LineAlignment = StringAlignment.Center;    // 垂直对齐方式
                    switch (SubTitleAlign)                                  // 水平对齐方式
                    
                        case EAlign.center:
                            stringFormat.Alignment = StringAlignment.Center;
                            break;
                        case EAlign.right:
                            stringFormat.Alignment = StringAlignment.Far;
                            break;
                        default:
                            stringFormat.Alignment = StringAlignment.Near;
                            break;
                    

                    rectF = new RectangleF(Start_X + (float)SubTitleOffset, Start_Y, (float)(ChartWidth - 4), sizeF.Height);  // 文字的矩形
                    g.DrawString(SubTitle, SubTitleFont, brush, rectF, stringFormat);                                               // 绘制副标题
                    Start_Y += sizeF.Height + 3f;                                                                             // 设置Y起点值 + 3px
                
            

        

        /// <summary>
        /// 绘制图表--绘制图例
        /// </summary>
        private void DrawChart_Legend()
        
            // 计算项目颜色
            int tmIndex = 0;
            for (int m = 0; m < ChartDataArray.Count; m++)
            
                tmIndex = m % ChartColor.Length;
                ChartDataArray[m].ItemColor = ChartColor[tmIndex];
            

            // 图例的高度最大40px 3排
            if (ShowLegend)
            
                // 计算文字大小 
                int LegendCount = ChartDataArray.Count;
                Font tFont = new Font("宋体", 9);
                for (int t = 0; t < LegendCount; t++)
                
                    SizeF tmSize = new SizeF();
                    tmSize = g.MeasureString(ChartDataArray[t].Name, tFont);
                    ChartDataArray[t].NameSize = tmSize;
                

                #region 绘制一排图例

                // 首先判定一行够不够
                float largMax = 0;
                for (int t = 0; t < LegendCount; t++)
                
                    if (t == 0)
                        largMax += ChartDataArray[t].NameSize.Width;
                    else
                        largMax += (35f + ChartDataArray[t].NameSize.Width);
                

                if (largMax <= End_X - Start_X) // 图例只需一排
                
                    End_Y -= 12.0f;
                    float tmX = (End_X - Start_X - largMax) / 2 + Start_X;
                    float tmY = End_Y;
                    for (int n = 0; n < LegendCount; n++)
                    
                        g.FillRectangle(new SolidBrush(ChartDataArray[n].ItemColor), tmX, tmY + 1, 15, 10);
                        tmX += 20;
                        g.DrawString(ChartDataArray[n].Name, new Font("宋体", 9), new SolidBrush(Color.Black), tmX, tmY);
                        tmX += 15 + ChartDataArray[n].NameSize.Width;
                    
                

                #endregion

                #region 绘制多排图例

                // 图例最多绘制三排
                else
                

                    bool TwoLine = true;                     // 是否两行:true 是; false: 否,为三行

                    // 判定两排还是三排
                    float tmBX = Start_X - 5;
                    int tmBC = (int)Math.Ceiling((double)LegendCount / 2);
                    for (int T = 0; T < tmBC; T++)
                    
                        float tmBW1 = -1F, tmBW2 = -1F, tmBM = 0F;
                        tmBW1 = ChartDataArray[T * 2].NameSize.Width;
                        if (ChartDataArray.Count > (T * 2 + 1))
                            tmBW2 = ChartDataArray[T * 2 + 1].NameSize.Width;
                        tmBM = tmBW1 > tmBW2 ? tmBW1 : tmBW2;
                        tmBX += 35 + tmBM;
                        if (tmBX > (End_X + 5))
                        
                            TwoLine = false;
                            break;
                        
                    

                    // 绘制两排图例
                    if (TwoLine)
                    
                        End_Y -= 24.0f;
                        float tmTX = (End_X + 10 - tmBX + Start_X + 5) / 2;       // 开始位置保持两排水平居中
                        float tmTY = End_Y;
                        int tmTM = (int)Math.Ceiling((double)LegendCount / 2);

                        // 绘制两排图例
                        for (int T = 0; T < tmTM; T++)
                        
                            float tmTW1 = -1F, tmTW2 = -1F, tmTW3 = 0F;
                            tmTW1 = ChartDataArray[T * 2].NameSize.Width;
                            if (ChartDataArray.Count > (T * 2 + 1))
                                tmTW2 = ChartDataArray[T * 2 + 1].NameSize.Width;
                            tmTW3 = tmTW1 > tmTW2 ? tmTW1 : tmTW2;

                            // 绘制第一排图例
                            g.FillRectangle(new SolidBrush(ChartDataArray[T * 2].ItemColor), tmTX, tmTY + 1, 15, 10);
                            g.DrawString(ChartDataArray[T * 2].Name, new Font("宋体", 9), new SolidBrush(Color.Black), (tmTX + 20), tmTY);

                            // 绘制第二排图例
                            if (tmTW2 > 0)
                            
                                g.FillRectangle(new SolidBrush(ChartDataArray[T * 2 + 1].ItemColor), tmTX, (tmTY + 16 + 1), 15, 10);
                                g.DrawString(ChartDataArray[T * 2 + 1].Name, new Font("宋体", 9), new SolidBrush(Color.Black), (tmTX + 20), (tmTY + 16));
                            
                            tmTX += 35 + tmTW3;
                        
                    

                    // 绘制三排图例
                    else
                    
                        End_Y -= 40.0f;
                        // 如果三排还不够,那么就不管了,绘制超出范围就超出范围
                        float tmSX = Start_X - 5;
                        float tmSY = End_Y;
                        int tmSC = (int)Math.Ceiling((double)LegendCount / 3);
                        bool CanFlag = true;  // 三排是否足够

                        // 首先计算三排的能排下的居中位置
                        for (int n = 0; n < tmSC; n++)
                        
                            float tmSW1 = -1F, tmSW2 = -1F, tmSW3 = -1F, tmSW4 = 0F;
                            tmSW1 = ChartDataArray[n * 3].NameSize.Width;
                            if (ChartDataArray.Count > (n * 3 + 1))
                                tmSW2 = ChartDataArray[n * 3 + 1].NameSize.Width;
                            if (ChartDataArray.Count > (n * 3 + 2))
                                tmSW3 = ChartDataArray[n * 3 + 2].NameSize.Width;
                            tmSW4 = tmSW1 > tmSW2 ? tmSW1 : tmSW2;
                            tmSW4 = tmSW4 > tmSW3 ? tmSW4 : tmSW3;
                            tmSX += 35 + tmSW4;
                            if (tmSX > (End_X + 5))
                            
                                CanFlag = false;
                                break;
                            
                        

                        // 再次执行三排绘制
                        if (CanFlag)             // 三排足够,则设置居中开始位置
                            tmSX = (End_X + 10 - tmSX + Start_X + 5) / 2;
                        else
                            tmSX = Start_X - 5;  // 三排排不下的情况就从5px 开始

                        for (int n = 0; n < tmSC; n++)
                        
                            float tmSW1 = -1F, tmSW2 = -1F, tmSW3 = -1F, tmSW4 = 0F;
                            tmSW1 = ChartDataArray[n * 3].NameSize.Width;
                            if (ChartDataArray.Count > (n * 3 + 1))
                                tmSW2 = ChartDataArray[n * 3 + 1].NameSize.Width;
                            if (ChartDataArray.Count > (n * 3 + 2))
                                tmSW3 = ChartDataArray[n * 3 + 2].NameSize.Width;
                            tmSW4 = tmSW1 > tmSW2 ? tmSW1 : tmSW2;
                            tmSW4 = tmSW4 > tmSW3 ? tmSW4 : tmSW3;

                            // 绘制第一排图例
                            g.FillRectangle(new SolidBrush(ChartDataArray[n * 3].ItemColor), tmSX, (tmSY + 1), 15, 10);
                            g.DrawString(ChartDataArray[n * 3].Name, new Font("宋体", 9), new SolidBrush(Color.Black), (tmSX + 20), tmSY);

                            // 绘制第二排图例
                            if (tmSW2 > 0)
                            
                                g.FillRectangle(new SolidBrush(ChartDataArray[n * 3 + 1].ItemColor), tmSX, (tmSY + 16 + 1), 15, 10);
                                g.DrawString(ChartDataArray[n * 3 + 1].Name, new Font("宋体", 9), new SolidBrush(Color.Black), (tmSX + 20), (tmSY + 16));
                            

                            // 绘制第三排图例
                            if (tmSW3 > 0)
                            
                                g.FillRectangle(new SolidBrush(ChartDataArray[n * 3 + 2].ItemColor), tmSX, (tmSY + 32 + 1), 15, 10);
                                g.DrawString(ChartDataArray[n * 3 + 2].Name, new Font("宋体", 9), new SolidBrush(Color.Black), (tmSX + 20), (tmSY + 32));
                            

                            tmSX += 35 + tmSW4;
                        
                    
                

                #endregion
            
        

        /// <summary>
        /// 绘制图表--绘制X轴标
        /// </summary>
        /// <param name="g"></param>
        private void DrawChart_XAxisText()
        
            // X轴标就不绘制了,因为空间不够,所以不执行X轴标的绘制
        

        /// <summary>
        /// 绘制图表--绘制Y轴标
        /// </summary>
        private void DrawChart_YAxisText()
        
            if (ChartType != EChartType.Pie)
            
                if (YAxisText != null && YAxisText.Trim() != "")
                
                    brush = new SolidBrush(Color.Gray);
                    stringFormat = new StringFormat();                                    // 格式化字符串
                    stringFormat.LineAlignment = StringAlignment.Near;                    // 垂直对齐方式
                    stringFormat.Alignment = StringAlignment.Near;                        // 水平对齐方式
                    SizeF sizeF = g.MeasureString(YAxisText, new Font("宋体", 9));        // 测量文字大小
                    rectF = new RectangleF(Start_X, Start_Y, sizeF.Width, sizeF.Height);  // 文字外围矩形
                    g.TranslateTransform((Start_X - Start_Y), (Start_X + Start_Y + sizeF.Width));    // 设置位置移动 X,Y 
                    g.RotateTransform(270);                                                          // 旋转270度  以左上角作为旋转原点
                    g.DrawString(YAxisText, new Font("宋体", 9), brush, rectF, stringFormat);
                    g.ResetTransform();

                    Start_X += sizeF.Height + 2;                                          // 加2个像素
                
            
        

        /// <summary>
        /// 绘制图表--绘制坐标轴
        /// </summary>
        private void DrawChart_Axis()
        
            // 1、图表区下移10PX
            Start_Y += 10;

            // 2、计算坐标轴参数
            Calc_XScaleHeight();
            Calc_YScaleValue();

            // 3、计算原点坐标值
            AxisZeroPt = new PointF(0f, 0f); // 坐标轴原点坐标
            AxisZeroPt.X = Start_X + myYScaleMaxWidth;
            AxisZeroPt.Y = End_Y - myXScaleMaxHeight;

            // 3.1、绘制坐标轴
            Pen pen2 = new Pen(Color.FromKnownColor(KnownColor.ControlDark), 2f);
            g.DrawLine(pen2, (Start_X + myYScaleMaxWidth - 4f), (End_Y - myXScaleMaxHeight), End_X + 2, (End_Y - myXScaleMaxHeight));     // 绘制 X坐标轴
            g.DrawLine(pen2, (Start_X + myYScaleMaxWidth), (End_Y - myXScaleMaxHeight + 4f), (Start_X + myYScaleMaxWidth), Start_Y - 2);  // 绘制 Y坐标轴

            // 3.2、计算分段宽
            XScaleWidth = (End_X - Start_X - myYScaleMaxWidth) / XSplitNum;      // 计算X轴分段宽
            YScaleWidth = (End_Y - Start_Y - myXScaleMaxHeight) / YSplitNum;     // 计算Y轴分段宽

            // 3.3、绘制刻度值
            pen = new Pen(Color.LightGray, 1f);
            pen.DashStyle = DashStyle.Dash;
            for (int k = 0; k < XSplitNum; k++)    // 绘制X轴刻度线 刻度值
            
                // 绘制X轴刻度线
                g.DrawLine(pen2, (AxisZeroPt.X + XScaleWidth * (k + 1)), AxisZeroPt.Y, (AxisZeroPt.X + XScaleWidth * (k + 1)), AxisZeroPt.Y + 4f);

                // 绘制X轴刻度值
                g.TranslateTransform(AxisZeroPt.X + XScaleWidth * k + 15f * XRotateAngle / 90 + 4f, AxisZeroPt.Y + 4f);  // 平移原点
                g.RotateTransform(XRotateAngle, MatrixOrder.Prepend);                                                    // 旋转图像
                g.DrawString(XScaleValues[k], new Font("宋体", 9f), new SolidBrush(Color.Black), 0, 0);                  // 绘制字符
                g.ResetTransform();
            

            for (int k = 0; k < YSplitNum; k++)
            
                // 绘制Y轴刻度线
                g.DrawLine(pen2, AxisZeroPt.X - 4, (AxisZeroPt.Y - YScaleWidth * (k + 1)), AxisZeroPt.X, (AxisZeroPt.Y - YScaleWidth * (k + 1)));

                // 绘制Y轴刻度值
                string tmYvalue = (YScale_StartValue + k * YScale_SplitValue).ToString();
                SizeF tmF = g.MeasureString(tmYvalue, new Font("宋体", 9));
                g.DrawString(tmYvalue, new Font("宋体", 9), new SolidBrush(Color.Black), (AxisZeroPt.X - tmF.Width - 4), (AxisZeroPt.Y - YScaleWidth * k - tmF.Height / 2 + 1));

                if (k == YSplitNum - 1)
                
                    tmYvalue = (YScale_StartValue + (k + 1) * YScale_SplitValue).ToString();
                    tmF = g.MeasureString(tmYvalue, new Font("宋体", 9));
                    g.DrawString(tmYvalue, new Font("宋体", 9), new SolidBrush(Color.Black), (AxisZeroPt.X - tmF.Width - 4), (AxisZeroPt.Y - YScaleWidth * (k + 1) - tmF.Height / 2 + 1));
                
            


            // 3.4、绘制网格线
            if (ShowGrid)
            
                for (int k = 1; k <= YSplitNum; k++)  // 绘制X轴平行横向辅助线
                    g.DrawLine(pen, AxisZeroPt.X + 1, (AxisZeroPt.Y - YScaleWidth * k), End_X, (AxisZeroPt.Y - YScaleWidth * k));

                for (int k = 1; k <= XSplitNum; k++)  // 绘制Y轴平行纵向辅助线
                    g.DrawLine(pen, (AxisZeroPt.X + XScaleWidth * k), Start_Y, (AxisZeroPt.X + XScaleWidth * k), AxisZeroPt.Y - 1);
            

            pen2.Dispose();
        

        /// <summary>
        /// 绘制曲线图
        /// </summary>
        private void DrawChart_Curve()
        
            g.SmoothingMode = SmoothingMode.HighQuality;
            g.TextRenderingHint = TextRenderingHint.ClearTypeGridFit;
            g.PixelOffsetMode = System.Drawing.Drawing2D.PixelOffsetMode.Half;

            int tmLength = 0;
            PointF[] CurvePointF = new PointF[tmLength];
            foreach (EChartData iItem in this.ChartDataArray)
            
                tmLength = iItem.Values.Count;
                CurvePointF = new PointF[tmLength];
                pen = new Pen(iItem.ItemColor, 2.0f);
                for (int rr = 0; rr < iItem.Values.Count; rr++)
                
                    double dbValue = iItem.Values[rr];
                    CurvePointF[rr].X = AxisZeroPt.X + XScaleWidth * rr + XScaleWidth / 2;
                    CurvePointF[rr].Y = AxisZeroPt.Y - (float)((dbValue - YScale_StartValue) / YScale_SplitValue) * YScaleWidth;
                

                // 绘制曲线
                g.DrawCurve(pen, CurvePointF, LineTension);

                // 绘制辅点
                for (int tt = 0; tt < CurvePointF.Length; tt++)
                
                    // 点标数据值
                    string tmValStr = iItem.Values[tt].ToString();

                    // 绘制数据点
                    g.FillEllipse(new SolidBrush(iItem.ItemColor), CurvePointF[tt].X - 3, CurvePointF[tt].Y - 3, 6, 6);

                    // 绘制数据值
                    SizeF tmValueSize = g.MeasureString(tmValStr, new Font("Arial", 9));
                    g.DrawString(tmValStr, new Font("Arial", 9), new SolidBrush(iItem.ItemColor), (CurvePointF[tt].X - tmValueSize.Width / 2), (CurvePointF[tt].Y - tmValueSize.Height - 2f));
                
            
        

        /// <summary>
        /// 绘制柱状图
        /// </summary>
        private void DrawChart_Bar()
        
            g.SmoothingMode = SmoothingMode.HighQuality;
            int tmLen = ChartDataArray.Count;                       // 柱形条目总数
            float tmBarWidth = XScaleWidth / (tmLen * 2 + 1);    // 每条柱形宽度 平均分配
            if (tmBarWidth < 2)
            
                tmBarWidth = 2f;
            

            for (int kk = 0; kk < this.ChartDataArray.Count; kk++)
            
                EChartData iItem = this.ChartDataArray[kk];
                pen = new Pen(Color.FromKnownColor(KnownColor.ControlDark), 1.0f);
                for (int rr = 0; rr < iItem.Values.Count; rr++)
                
                    RectangleF barRect = new RectangleF(0, 0, 0, 0);
                    double dbValue = iItem.Values[rr];
                    barRect.X = AxisZeroPt.X + XScaleWidth * rr + (tmBarWidth * ((kk + 1) * 2 - 1));
                    barRect.Y = AxisZeroPt.Y - (float)((dbValue - YScale_StartValue) / YScale_SplitValue) * YScaleWidth;
                    barRect.Width = tmBarWidth;
                    barRect.Height = AxisZeroPt.Y - barRect.Y;

                    // 绘制柱形
                    g.DrawRectangle(pen, barRect.X, barRect.Y, barRect.Width, barRect.Height);

                    brush = new SolidBrush(iItem.ItemColor);
                    g.FillRectangle(brush, barRect.X + 1, barRect.Y + 1, barRect.Width - 2, barRect.Height - 2);

                    // 绘制数据
                    SizeF tmValueSize = g.MeasureString(dbValue.ToString(), new Font("Arial", 9));
                    g.DrawString(dbValue.ToString(), new Font("Arial", 9), new SolidBrush(iItem.ItemColor), (barRect.X + tmBarWidth / 2 - tmValueSize.Width / 2), (barRect.Y - tmValueSize.Height - 2f));
                
            
        

        /// <summary>
        /// 绘制图表--绘制饼状图
        /// </summary>
        private void DrawChart_Pie()
        
            // 上下预留20 PX 为了标记饼图的数据值        
            Start_Y += 20;
            End_Y -= 20;

            g.SmoothingMode = SmoothingMode.HighQuality;
            g.TextRenderingHint = TextRenderingHint.ClearTypeGridFit;
            g.PixelOffsetMode = System.Drawing.Drawing2D.PixelOffsetMode.Half;

            // 矩形坐标点
            PointF piePoint = new PointF(0, 0);
            float tmPieW = End_X - Start_X;
            float tmPieH = End_Y - Start_Y;
            float tmPieR = tmPieW < tmPieH ? tmPieW / 2 : tmPieH / 2;  // 半径

            piePoint.X = Start_X + tmPieW / 2 - tmPieR;
            piePoint.Y = Start_Y + tmPieH / 2 - tmPieR;

            // 圆心坐标点
            PointF pieZero = new PointF(piePoint.X + tmPieR, piePoint.Y + tmPieR);

            // 绘制外围圆
            pen = new Pen(Color.FromKnownColor(KnownColor.ControlDark), 1.5f);
            g.DrawEllipse(pen, piePoint.X - 5, piePoint.Y - 5, (tmPieR + 5) * 2, (tmPieR + 5) * 2);

            // 计算总数
            double pieCountValue = 0;
            foreach (EChartData iItem in this.ChartDataArray)
            
                if (iItem.Values.Count >= 1)
                    pieCountValue += iItem.Values[0];
            

            // 绘制扇形
            if (pieCountValue > 0)
            
                float curAngle = 0; // 占比角度
                float sumAngle = 0; // 总角度和

                foreach (EChartData iItem in this.ChartDataArray)
                
                    if (iItem.Values.Count >= 1)
                        curAngle = (float)(iItem.Values[0] / pieCountValue * 360);
                    else
                        curAngle = 0;

                    // 填充笔刷
                    brush = new SolidBrush(iItem.ItemColor);

                    // 绘制弧形
                    g.FillPie(brush, piePoint.X, piePoint.Y, tmPieR * 2, tmPieR * 2, sumAngle, curAngle);

                    // 绘制弧线
                    g.DrawPie(pen, piePoint.X, piePoint.Y, tmPieR * 2, tmPieR * 2, sumAngle, curAngle);

                    // 绘制数据
                    float tmPre = (float)Math.Round((iItem.Values[0] / pieCountValue) * 100, 2);
                    string tmStr = tmPre.ToString() + "%" + " [" + iItem.Values[0].ToString() + "]";

                    // 内圆信息
                    double relCur_X = tmPieR * Math.Cos((360 - sumAngle - curAngle / 2) * Math.PI / 180);
                    double relCur_Y = tmPieR * Math.Sin((360 - sumAngle - curAngle / 2) * Math.PI / 180);
                    double cur_X = relCur_X + pieZero.X;
                    double cur_Y = pieZero.Y - relCur_Y;
                    PointF cur_Point = new PointF((float)cur_X, (float)cur_Y);  // 内圆上弧线中间点的坐标

                    // 外圆信息
                    float largerR = tmPieR + 10;
                    double relLarg_X = largerR * Math.Cos((360 - sumAngle - curAngle / 2) * Math.PI / 180);
                    double relLarg_Y = largerR * Math.Sin((360 - sumAngle - curAngle / 2) * Math.PI / 180);
                    double largerX = relLarg_X + pieZero.X;
                    double largerY = pieZero.Y - relLarg_Y;
                    PointF larger_Point = new PointF((float)largerX, (float)largerY);

                    SizeF calcSize = new SizeF(0, 0);

                    // 绘制链接斜线(内圆到外圆弧度中间点的连接线)
                    g.DrawLine(new Pen(new SolidBrush(iItem.ItemColor), 1.5f), cur_Point, larger_Point);                                               // 斜线

                    // 绘制横向线条
                    //*以下是对四个象限、以及对90度、180度、270度和360度的判断*//
                    float tmCurIf = sumAngle + curAngle / 2;
                    if (tmCurIf <= 90)
                    
                        g.DrawLine(new Pen(new SolidBrush(iItem.ItemColor), 1.5f), larger_Point.X, larger_Point.Y, larger_Point.X + 15f, larger_Point.Y);  // 横线
                        g.DrawString(tmStr, new Font("Arial", 9), new SolidBrush(iItem.ItemColor), larger_Point.X + 15f, larger_Point.Y - 8f);             // 文字
                    
                    else if (tmCurIf > 90 && tmCurIf <= 180)
                    
                        calcSize = g.MeasureString(tmStr, new Font("Arial", 9));
                        g.DrawLine(new Pen(new SolidBrush(iItem.ItemColor), 1.5f), larger_Point.X, larger_Point.Y, larger_Point.X - 15f, larger_Point.Y);       // 横线
                        g.DrawString(tmStr, new Font("Arial", 9), new SolidBrush(iItem.ItemColor), larger_Point.X - 15f - calcSize.Width, larger_Point.Y - 8f); // 文字
                    
                    else if (tmCurIf > 180 && tmCurIf <= 270)
                    
                        calcSize = g.MeasureString(tmStr, new Font("Arial", 9));
                        g.DrawLine(new Pen(new SolidBrush(iItem.ItemColor), 1.5f), larger_Point.X, larger_Point.Y, larger_Point.X - 15f, larger_Point.Y);       // 横线
                        g.DrawString(tmStr, new Font("Arial", 9), new SolidBrush(iItem.ItemColor), larg

以上是关于C# 报表设计器 (winform 设计端)开发与实现生成网页的HTML报表 开放源码及调试的主要内容,如果未能解决你的问题,请参考以下文章

C# 报表设计器 (winform 设计端)开发与实现生成网页的HTML报表 开放源码及调试

winform 中crystalReport报表1对多设计

C# Winform 设计器 !!

C# winform 设计 如何相对居中

相对传统桌面设计器,在线报表设计器价值何在?

在C#中,设计grid++report报表的具体步骤是啥??帮助文档感觉好乱,自己没有基础,求具体步骤