在項目開發中,往往會碰到一些非常規的需求,每次碰到這種情況,都需要花費時間來整理自己的思路,然后參考網絡上其他人的實現方式或者作法,有時候可以找到一些相同的模塊進行改進即可符合需求,但往往很多是需要自己潛心研究,然后提煉優化,雖然探索過程還是比較開心,不過時間肯定是需要花不少的。我每次碰到這種情況,都會沉下心來,力求把這種的模塊做得更好一點,方便以后的重用,這樣每次抱着這樣的態度,着實積累了不少好的東西,也可以為后面的項目夯實基礎。
在一次Winform的項目開發過程中,客戶需要對一些體檢數據等參數進行曲線展示,其實圖表控件有很多,但是我印象比較深的還是開源的ZedGraph控件,這個既可以用在Web上,也可以用在Winform上的開源控件,有着簡單易用的特點,因此我會先考慮是否可以滿足要求。在需求中,我需要定制顯示曲線報表的內容,按照每行一個人員的數據,然后再每行中展現該人員的相關圖表信息,而且這種的報表要可以實現打印的功能。在經過一段時間的摸索及實現提煉,得到了比較滿意的效果,先來進行總體的介紹先把。
通過把好的思路,有用的技巧進行積累整合到Winform開發框架中,方便自己,也方便別人,提高工作效率。
1、按每行一個用戶的數據顯示曲線報表圖形
一行一個人員的曲線數據,可以對同一曲線項目進行對比,方便用戶的實際業務對比操作。
2、每個曲線圖形可以雙擊打開,進行放大縮小的操作,方便用戶查看。
由於在一個界面中展示多個圖表圖形的時候,會比較小,為了更直觀顯示曲線數據,可以通過單獨打開一個新的窗口進行曲線縮放操作,支持鼠標的滾動放大縮小,同時ZedGraph支持繪圖點的信息提示,非常友好。
3、提供自定義打印及文檔導出功能
由於用戶控件是自定義組裝的,因此要實現自定義的打印功能才可以,這個自定義打印的東西確實需要慢慢測試研究,這個地方花了不少時間。
通過在DevExpress打印界面中展示預覽效果,方便可以進行打印確認操作,以及預覽最終的效果,並支持把文檔導出到PDF或者圖片中,非常方便易用。
以上就是這個曲線報表的主要幾個特點,不過這樣的曲線,基本上能夠滿足我們日常的一些數據曲線的展現的了。
實現上我們需要把需求和界面拆分,首先我們在一個設計主界面,在住界面上防止一個TableLayout的布局控件,方便我們動態添加每個單一的控件進去。
4、曲線報表具體實現過程及思路
1)設計報表顯示主界面
2)設計曲線報表組件
然后設計一個空白的布局FlowLayout控件,用來擺放一個或者多個的曲線報表項目,例如體重曲線、視力曲線、血壓曲線等項目的,實現代碼如下所示。
public void BindData() { switch (CurveData.CurveType) { case CurveType.體重: BindWeight(); break; case CurveType.身長: BindHeight(); break; case CurveType.脈搏: BindPulse(); break; case CurveType.血壓: BindBlood(); break; case CurveType.視力: BindSight(); break; case CurveType.暗適應時間: BindDarkAdapTime(); break; case CurveType.體溫: BindTemperature(); break; case CurveType.全部: #region 全部 if (CurveData.CheckType == CheckType.季度小體檢) { BindWeight(); BindPulse(); BindBlood(); BindSight(); BindDarkAdapTime(); } else if (CurveData.CheckType == CheckType.年度大體檢) { BindWeight(); BindHeight(); BindPulse(); BindBlood(); BindSight(); } else if (CurveData.CheckType == CheckType.飛行前體檢) { BindTemperature(); BindPulse(); BindBlood(); } break; #endregion } }
private void BindWeight() { DataTable dt = null; if (CurveData.CheckType == CheckType.年度大體檢) { dt = BLLFactory<LargeCheckSurgical>.Instance.GetWeightData(CurveData.StartDate, CurveData.EndDate, CurveData.PilotID); } else if (CurveData.CheckType == CheckType.季度小體檢) { dt = BLLFactory<SmallCheck>.Instance.GetWeightData(CurveData.StartDate, CurveData.EndDate, CurveData.PilotID); } WeightCurve curve = new WeightCurve(); curve.CurveData = CurveData; curve.dataTable = dt; this.layoutPanel1.Controls.Add(curve); }
其他代碼不在贅述。
3)設計曲線項目組件
由於曲線報表涉及很多展示的項目,每項又有一些不同,因此我們為不同的項目設計一個組件,如體重曲線如下所示,在一個自定義控件上面放置一個ZedGraph組件,設計好這個組件的相關屬性和事件。
這個控件默認是英文的,所以如果需要使用中文菜單,需要自己漢化一下代碼,然后編譯出來自己使用即可。
實現代碼如下所示
GraphPane myPane = zgc.GraphPane; myPane.CurveList.Clear(); // 設置標題及坐標軸的說明 myPane.Title.Text = string.Format("【{0}】體重曲線", CurveData.PilotName); myPane.XAxis.Title.Text = "體檢日期"; myPane.YAxis.Title.Text = "體重(Kg)"; PointPairList list = new PointPairList(); foreach(DataRow row in dataTable.Rows) { DateTime checkDate = Convert.ToDateTime(row["CheckDate"].ToString()); double x = (double) new XDate(checkDate); double y = Convert.ToInt32(row["Weight"].ToString()); list.Add(x, y); } LineItem myCurve = myPane.AddCurve("體重", list, Color.Red, SymbolType.Diamond); myCurve.Symbol.Fill = new Fill(Color.White);
4)設計圖表打印模塊
打印的時候,需要自己在打印原件上進行圖形的繪制,這一個是比較復雜的調試過程,開始總是想着是否可以把控件打印出來就OK,可是這種操作,一旦界面遮擋,就打印不出實際的效果了,所以只好類似繪圖一樣,使用自定義繪制方式。
這樣我計算好每個控件的大小尺寸(包括Lable控件、曲線圖表控件),然后挨着繪制即可,主要代碼如下所示。
protected virtual void DrawRow(BrickGraphics graph, int rowIndex, int col, Control ctrl, float left) { graph.BackColor = Color.White; RectangleF bounds = new RectangleF(left, 0, ctrl.Width, ctrl.Height); bounds.Y = (rowIndex - 1) * bounds.Height; if (ctrl is Label) { TextBrick brick = graph.DrawString(ctrl.Text, bounds); brick.HorzAlignment = DevExpress.Utils.HorzAlignment.Center; brick.VertAlignment = DevExpress.Utils.VertAlignment.Center; const int LeftPadding = 4; brick.Padding = new PaddingInfo(LeftPadding, brick.Padding.Right, brick.Padding.Top, brick.Padding.Bottom); } else { int width = ctrl.Size.Width; int height = ctrl.Size.Height; Bitmap bm = new Bitmap(width, height); ctrl.DrawToBitmap(bm, new Rectangle(0, 0, width, height)); ImageBrick brick = graph.DrawImage(bm, bounds); brick.SizeMode = ImageSizeMode.ZoomImage; } }
好了,整個曲線報表的顯示效果及實現思路及部分核心代碼,都已經介紹完畢了,在整個過程中,除了經驗外,我覺得最重要的就是要細心、耐心及用心,項目開發就是把各種技巧、各種思路都集中起來,才可以快速高效的開發出高質量、客戶反映好的項目出來。