在前面的一些随笔中,介绍了很多个人Winform框架的特性,上篇随笔《Winform开发框架之通用高级查询模块》对其中的通用高级模块进了一个整理说明,本篇继续介绍Winform开发框架重要的一个特性之统计图表的实现。统计图表在不少项目均可能用到,集成到框架中,更方便你们对一些图表项目的设计理解以及功能的重用。在通常的传统的框架中,能够采用ZedGraph开源控件或者微软自带的MSChart进行图表设计,DevExpress控件套件有本身的图表控件,本篇主要介绍基于DevExpress控件的图表控件进行图表设计,进一步丰富个人Winform开发框架。html
这里指的普通统计图表,只是对表某一项目进行单一的统计,能够从饼状图、柱状图的图表中体现这些项目各自所占的比例和数值,在个人普通统计图表模块中,包括了饼状图、柱状图和数据表格,这样更方便对数据进行全面的分析和查看。整个模块是能够重用的,除了制定字段属性就能够比较合理的展示出不一样分类项目的统计效果了,具体效果图以下所示。node
上面的统计图表中,还包含了下面两个功能模块,以下所示。框架
经过以上饼图、柱状图以及数据报表,咱们能够很清晰地看到各类统计项目的数值和总体直观的展示图表了。post
因为对这类型的图表进行了自定义控件的封装,所以调用很是方便,调用代码以下所示。this
1)绑定统计树形列表url
为了给用户展现框架(或者项目)支持的报表项目,咱们须要在左边的树形列表中初始化一些报表项目,具体代码以下所示。spa
#region 备件信息统计 this.treeItemDetail.Nodes.Clear(); TreeNode node; node = new TreeNode("备件属类统计", 0, 0); node.Tag = "ItemBigType"; this.treeItemDetail.Nodes.Add(node); node = new TreeNode("备件类别统计", 0, 0); node.Tag = "ItemType"; this.treeItemDetail.Nodes.Add(node); node = new TreeNode("备件材质统计", 0, 0); node.Tag = "Material"; this.treeItemDetail.Nodes.Add(node); node = new TreeNode("备件名称统计", 0, 0); node.Tag = "ItemName"; this.treeItemDetail.Nodes.Add(node); node = new TreeNode("所属库房统计", 0, 0); node.Tag = "WareHouse"; this.treeItemDetail.Nodes.Add(node); node = new TreeNode("所属部门统计", 0, 0); node.Tag = "Dept"; this.treeItemDetail.Nodes.Add(node); //自定义输入字段统计 node = new TreeNode("备件数据动态统计", 0, 0); node.Tag = "Customed"; this.treeItemDetail.Nodes.Add(node); #endregion
上面的树形列表中,咱们给Tag赋值,通常状况下是表字段的名称,有些特殊的,则采用Customed来表示,咱们响应树形列表控件的操做,根据Tag的不一样,切换到不一样的报表自定义控件进行展示(包括自定义动态项目统计图表和普通统计图表项目)。设计
因为咱们对图表的展示进行了比较合理的封装,所以基本上普通的图表统计项目,只是字段名称的不一样。3d
对于普通统计图表项目FrmCategoryReport,这个是一个自定义控件来的,方便动态加载到右边的展现Panel区域,这样咱们就能根据不一样类型的报表动态加载。code
建立图表的代码以下所示。
private DataTable dt = null; private void BindData() { if (string.IsNullOrEmpty(FieldName)) return; //设置报表标题 this.Text = ReportTitle; this.lblReportTitle.Text = ReportTitle; this.chartPie.Series.Clear(); this.chartBar.Series.Clear(); string where = GetConditionSql(); dt = BLLFactory<ItemDetail>.Instance.GetReportData(FieldName, where); this.gridControl1.DataSource = dt; if (dt != null && dt.Rows.Count > 0) { this.chartPie.DataSource = dt; Series pieSeries = CreateSeries(dt, DevExpress.XtraCharts.ViewType.Pie3D, NumericFormat.Percent); chartPie.Series.Add(pieSeries); chartPie.Legend.Visible = true; PieSeriesLabel label = pieSeries.Label as PieSeriesLabel; ((PiePointOptions)label.PointOptions).PercentOptions.PercentageAccuracy = 4; ((PiePointOptions)label.PointOptions).PercentOptions.ValueAsPercent = true; label.Position = PieSeriesLabelPosition.TwoColumns; //设置饼图上lable的显示方式,此方式将独立出一个列显示lable (pieSeries.View as DevExpress.XtraCharts.Pie3DSeriesView).ExplodeMode = PieExplodeMode.All; //突出显示饼块 (pieSeries.View as DevExpress.XtraCharts.Pie3DSeriesView).ExplodedDistancePercentage = 5; //(pieSeries.View as DevExpress.XtraCharts.PieSeriesView).RuntimeExploding = true; //设置了他,你就能够把你喜欢的饼块拖出来。。。 this.chartBar.DataSource = dt; chartBar.Series.Add(CreateSeries(dt, DevExpress.XtraCharts.ViewType.Bar, NumericFormat.General)); chartBar.Legend.Visible = false; chartBar.SeriesTemplate.LabelsVisibility = DefaultBoolean.True; } this.xtraTabControl1.SelectedTabPageIndex = 0; }
其中咱们注意到,建立图表的Series对象的方法,我进行了进一步的封装。
Series pieSeries = CreateSeries(dt, DevExpress.XtraCharts.ViewType.Pie3D, NumericFormat.Percent);
其中CreateSeries方法代码以下所示。
/// <summary> /// 建立图表的Series对象,能够指定相应的类型 /// </summary> /// <param name="dt">数据源</param> /// <param name="viewType">图表类型,如DevExpress.XtraCharts.ViewType.Pie3D,DevExpress.XtraCharts.ViewType.Bar</param> /// <param name="format">显示格式,如百分比NumericFormat.Percent,NumericFormat.General</param> /// <returns></returns> private Series CreateSeries(DataTable dt, DevExpress.XtraCharts.ViewType viewType, NumericFormat format) { Series series = new Series("Serices1 ", viewType); series.DataSource = dt; series.ArgumentScaleType = ScaleType.Qualitative; series.ArgumentDataMember = "argument"; series.ValueScaleType = ScaleType.Numerical; series.ValueDataMembers.AddRange(new string[] { "datavalue" }); series.PointOptions.PointView = PointView.ArgumentAndValues; series.PointOptions.ValueNumericOptions.Format = format; if (format == NumericFormat.Number) { //series.PointOptions.ValueNumericOptions.Precision = 0; } series.LabelsVisibility = DevExpress.Utils.DefaultBoolean.True;//显示标注标签 return series; }
在Winform开发框架中,我试图对备件仓库中不一样类型的设备进行一个库存统计,也获得了这类型的图表以下所示。
有时候,咱们对于表里面的数据,可能要对不一样类型的内容进行动态的统计,以肯定他们各自的比例状况,那么这些动态项目的统计图表就比较合适了,例如,对于病人资料的管理,咱们可能须要统计各类病种所占的比例或者各类职业类型的犯病率,这些不太肯定的统计项目,就须要一个可以支持动态项目的统计图表进行支撑,对于本Winform框架,为了较好呈现这个类型报表的意义,我选择了对备件类型所占的比例进行一个统计分析,获得下面的统计图表,以下所示。
上面的图表统计,除了可以根据一些条件进行限定查询范围外,还能够对一些预设的统计字段进行动态选取,而后根据字段里面的各类内容(统计项目)进行统计,这样就能够比较有效的统计出各类类型的数值和比例了。
动态项目的统计,主要是对不一样字段,以及对应不一样字段的内容进行一个条件分析,把它们的统计数字构造一个数据表格便可进行合理展示,以下部门代码所示。
string fieldName = fieldItem.Value; int totalCount = BLLFactory<ItemDetail>.Instance.GetRecordCount(where);//计算总人数 foreach (string searchItem in this.lstItems.Items) { string condition = string.Format("{0} like '%{1}%' ", fieldName, searchItem); if (!string.IsNullOrEmpty(where)) { condition += string.Format(" AND {0}", where); } int countValue = BLLFactory<ItemDetail>.Instance.GetRecordCount(condition);//计算总人数 countRepeat += countValue; row = dt.NewRow(); row[0] = searchItem; row[1] = countValue; dt.Rows.Add(row); }
有时候咱们可能须要对某年各个月份的数值进行对比统计,已看出各类统计项目的发展趋势或者对比效果,这就要求能够对多份数据进行合并展示,这种在图表展示中可使用多重坐标对比的统计图表模块进行展示,如我上篇随笔《DevExpress控件使用之多重坐标图形的绘制》就对这类型的图表统计进行了比较细致的分析和说明,相关的效果图以下所示。
在Winform框架里面,能够对某一年各月份的出入库数量进行一个分析,获得下面的统计图。
以上数据很少,展示可能不太好看,下面我给出我另外一个软件系统的界面,其中对病人的出入院记录进行一个统计对比分析,统计报表以下所示。
不少时候,咱们可能须要对呈现的报表进行一个打印和导出操做,对于DevExpress的ChartControl控件,打印操做很简单,你甚至能够用一行代码进行打印操做。
this.chartControl1.ShowPrintPreview(DevExpress.XtraCharts.Printing.PrintSizeMode.Zoom);
或者增长更复杂的定制操做,代码以下所示。
private void btnPrint_Click(object sender, EventArgs e) { //this.chartControl1.ShowPrintPreview(DevExpress.XtraCharts.Printing.PrintSizeMode.Zoom); DevExpress.XtraPrintingLinks.CompositeLink compositeLink = new DevExpress.XtraPrintingLinks.CompositeLink(); DevExpress.XtraPrinting.PrintingSystem ps = new DevExpress.XtraPrinting.PrintingSystem(); compositeLink.PrintingSystem = ps; compositeLink.Landscape = true; compositeLink.PaperKind = System.Drawing.Printing.PaperKind.A4; DevExpress.XtraPrinting.PrintableComponentLink link = new DevExpress.XtraPrinting.PrintableComponentLink(ps); ps.PageSettings.Landscape = true; link.Component = this.chartControl1; compositeLink.Links.Add(link); link.CreateDocument(); //创建文档 ps.PreviewFormEx.Show();//进行预览 }
对于导出报表,咱们 通常要求图文并茂,纯粹导出图表的图片或者列表,都是一件很简单的事情,可是要把它们整合一块儿,并进行合理的排版,这须要费一点心思才能作好。
首先咱们来介绍一下,通常图表控件都有导出Image图片类型的操做,DevExpress控件也不例外,它的操做代码以下所示。
//插入图片到Excel里面 using (MemoryStream stream = new MemoryStream()) { stream.Position = 0; ChartControl chart = (ChartControl)chartControl1.Clone(); chart.Size = new Size(800, 400); chart.ExportToImage(stream, ImageFormat.Jpeg); //进行存储操做 //worksheet.Pictures.Add(startRow, 0, stream); }
为了更好的整合几个图表和数据报表,咱们这里采用了Aspose.Cell控件进行代码操做,把这些图表动态整合到一个Excel文档里面进行导出,所有代码以下所示。
private void btnExport_Click(object sender, EventArgs e) { try { DataTable dt = this.gridControl1.DataSource as DataTable; if (dt == null || dt.Rows.Count == 0) { MessageDxUtil.ShowTips("没有数据须要导出!"); return; } string saveDocFile = FileDialogHelper.SaveExcel(string.Format("{0}.xls", ReportTitle), "C:\\"); if (!string.IsNullOrEmpty(saveDocFile)) { Workbook workbook = new Workbook(); Worksheet worksheet = workbook.Worksheets[0]; worksheet.PageSetup.Orientation = PageOrientationType.Landscape;//横向打印 worksheet.PageSetup.Zoom = 100;//以100%的缩放模式打开 worksheet.PageSetup.PaperSize = PaperSizeType.PaperA4; #region 表头及说明信息 Range range; Cell cell; string content; int colSpan = 3; range = worksheet.Cells.CreateRange(0, 0, 1, colSpan); range.Merge(); range.RowHeight = 20; range.Style = CreateTitleStyle(workbook); cell = range[0, 0]; cell.PutValue(ReportTitle); range = worksheet.Cells.CreateRange(1, 0, 1, colSpan); range.Merge(); range.RowHeight = 15; cell = range[0, 0]; content = string.Format("统计报表详细列表以下:"); cell.PutValue(content); #endregion #region 生成报表头部表格 Style headStyle = CreateStyle(workbook, true); Style normalStyle = CreateStyle(workbook, false); int startRow = 2; int startCol = 0; int index = 0; foreach (DataColumn col in dt.Columns) { range = worksheet.Cells.CreateRange(startRow, index, 2, 1); range.Merge(); range.Style = headStyle; cell = range[0, 0]; cell.PutValue(col.ColumnName); cell.Style = headStyle; index++; } #endregion //写入数据到Excel startRow = startRow + 2; for (int i = 0; i < dt.Rows.Count; i++) { startCol = 0; for (int j = 0; j < dt.Columns.Count; j++) { DataRow dr = dt.Rows[i]; cell = worksheet.Cells[startRow, startCol]; cell.PutValue(dr[j]); cell.Style = normalStyle; startCol++; } startRow++; } //写入图注 startRow += 1;//跳过1行 range = worksheet.Cells.CreateRange(startRow++, 0, 1, colSpan); range.Merge(); range.RowHeight = 15; cell = range[0, 0]; cell.PutValue("以曲线图展现以下:"); //插入图片到Excel里面 using (MemoryStream stream = new MemoryStream()) { stream.Position = 0; ChartControl chart = (ChartControl)chartControl1.Clone(); chart.Size = new Size(800, 400); chart.ExportToImage(stream, ImageFormat.Jpeg); worksheet.Pictures.Add(startRow, 0, stream); } workbook.Save(saveDocFile); if (MessageUtil.ShowYesNoAndTips("保存成功,是否打开文件?") == System.Windows.Forms.DialogResult.Yes) { System.Diagnostics.Process.Start(saveDocFile); } } } catch (Exception ex) { LogTextHelper.Error(ex); MessageUtil.ShowError(ex.Message); return; } }
导出Excel的效果以下所示。
下面是我对Winform开发框架大的方面的特性进行一个整理,但愿可以归纳整个框架的一些经常使用特性,较以前的图形,增长了高级查询模块,统计图表模块等内容。但愿你们批评指正。