在前面的一些隨筆中,介紹了很多個人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開發框架大的方面的特性進行一個整理,但願可以歸納整個框架的一些經常使用特性,較以前的圖形,增長了高級查詢模塊,統計圖表模塊等內容。但願你們批評指正。