一、需要嗎?
我們的假設前提有一下:
1)你是一個Winform開發者。
2)你現在要用Grid實現你的需求。
3)你們項目組不准用三方控件。
4)你的需求中就偏偏需要對信息的統計。
如果你具備了上述的條件,那么你需要它。統計信息往往在表格中是比較重要的地位的,下面我們來看如何來實現:
二、能實現嗎?
相對於其他的控件擴展,遇到這么個問題,我一開始真是無從下手;因為.Net的DataGridView本身就沒有實現統計行,那么想擴展就找不到一個支點。
我簡閱了很多的實現統計行的代碼,有使用panel的有、有使用雙DataGridView的;各式各樣,不缺乏好的方案,但是我覺得唯一的缺憾就是他們都不來自DataGridView的自身擴展,也只能算個變通的實現方法。
經過我仔細的思考,既然沒有現成的統計行,那么就利用Row來擴展,需要做到以下幾點;
1)能實現統計行,添加統計信息;
2)統計行的單元格與表格保持一致,隨着列寬的改變而改變,保持表格樣式。
3)統計行要始終保持在最下方,不能隨着排序等變動位置。
4)統計行的數據應該不跟一般的行一起獲取。
先說說我的實現方法吧:
1. 先實現一個SummaryRow和SummaryCell
1: namespace DataGridViewEx.DataGridViewExs.RowEx2: {
3: /// <summary>4: /// 統計行5: /// </summary>6: public class DataGridSummaryRowEx:DataGridViewRow7: {
8:
9: }
10:
11: /// <summary>12: /// 統計單元格13: /// </summary>14: public class DataGridSummaryCellEx : DataGridViewTextBoxCell15: {
16: protected override void OnClick(DataGridViewCellEventArgs e)17: {
18:
19: //base.OnClick(e);20: }
21:
22: public override bool ReadOnly23: {
24: get
25: {
26: return true;27: }
28: set
29: {
30: base.ReadOnly = value;31: }
32: }
33: }
34: }
2. 在DataGridViewEx的CellPainting等事件中把SummaryCell過濾,不做處理。
1: protected override void OnCellFormatting(DataGridViewCellFormattingEventArgs e)2: {
3: if (this.Rows[e.RowIndex].Cells[e.ColumnIndex] is utGridSummaryCell)4: return;5: //Mark:在這里執行注冊的程序6: this.CellFormatterRegister.RunFormatter(this.Columns[e.ColumnIndex].Name, e);7: //....8: }
3. 在 DataGridViewEx中的ColumnHeaderClick中處理,先Remove統計行,再添加統計行。(主要是解決排序的問題)
1: /// <summary>2: /// 在排序之前將統計行去除,使得排序不會根據統計行內容排序3: /// </summary>4: /// <param name="e"></param>5: protected override void OnColumnHeaderMouseClick(DataGridViewCellMouseEventArgs e)6: {
7: if (e.Button == System.Windows.Forms.MouseButtons.Left)8: this.RemoveSummaryRow();9: base.OnColumnHeaderMouseClick(e);10: if (e.Button == System.Windows.Forms.MouseButtons.Left)11: this.AppendSummaryRow();12: }
13:
14:
15: DataGridSummaryRowEx m_summaryRow = null;16:
17: private void RemoveSummaryRow()18: {
19: if (m_summaryRow == null) return;20: if (this.Rows.Contains(m_summaryRow))21: this.Rows.Remove(m_summaryRow);22: }
23:
24: private void AppendSummaryRow()25: {
26: if (m_summaryRow == null) return;27: this.RemoveSummaryRow();28: int index = this.Rows.Add(m_summaryRow);29: m_summaryRow = this.Rows[index] as DataGridSummaryRowEx;30: }
31:
32: /// <summary>33: /// 創建統計行,並且返回統計行對象,以便對單元格進行賦值信息34: /// </summary>35: /// <returns></returns>36: static Color m_summaryBackColor = Color.Linen;37: public DataGridSummaryRowEx CreateSummary()38: {
39: if (m_summaryRow == null)40: {
41: m_summaryRow = new DataGridSummaryRowEx();42:
43: //添加與column相同的列,只是這里的單元格是自擴展的。44: foreach (DataGridViewColumn col in this.Columns)45: {
46: m_summaryRow.Cells.Add(new DataGridSummaryCellEx());47: }
48: m_summaryRow.DefaultCellStyle.BackColor = m_summaryBackColor;
49: }
50: this.RemoveSummaryRow();51: this.AppendSummaryRow();52: return m_summaryRow;53: }
4. 看到那個CreateSummary 方法了嗎,就是用這個方法添加的:
1: protected void IniailzieData()2: {
3: for (int i = 0; i < 10; i++)4: {
5: this.dataGridViewEx1.Rows.Add(new object[] {6: false,"測試文本"+i,"","btn"+i7: });
8: }
9:
10: DataGridSummaryRowEx summaryRow = this.dataGridViewEx1.CreateSummary(); 11: summaryRow.Cells[0].Value = "合計"; 12: summaryRow.Cells[2].Value = 122;13: }
三、有更好的方法嗎?
先介紹一下我的實現原理吧:
1)設計一個CreateSummary方法在行尾添加一個統計行。
2)這個統計行,不使用DataGridView中的列信息,而是使用列數和列寬來使用SummaryCell來自定義一行。
3)這個統計行,在ColumnHeaderClick中先移除再添加,主要解決的是在排序之前把它移除,排序就不在內,然后添加到最后一行。
4)把這個行放出去,然后由外面來賦值,要實現自動統計還是比較麻煩的。
好了,介紹完我的實現方法,現求更好的方法,或者完善我的方法。
1) 我的方法中不能實現自動統計。
2) 我的方法中CreateSummary必須人為的在最后調用,所以不夠安全。
3) 我的方法中使用枚舉Rows時,也帶了統計行信息。
由於有了這么多弊端,所以現求大牛們能否思考如果解決我的這些問題,或者能否有更好的實現思路。
四、源碼及演示程序下載。
演示程序: 05[20120515]SummaryRow@DataGridViewEx.rar
開源項目:http://sourceforge.net/p/datagridviewex/code-0/3/tree/trunk/DataGridViewEx/