C#實現WinForm DataGridView控件支持疊加數據綁定


我們都知道WinForm DataGridView控件支持數據綁定,使用方法很簡單,只需將DataSource屬性指定到相應的數據源即可,但需注意數據源必須支持IListSource類型,這里說的是支持,而不是實現,是因為他既可以是實現了IListSource的類型,也可以是實現了IList的類型,例如:List類型,DataTable類型等,這里就不一一列舉了,今天我主要實現的功能如標題所描述的:實現WinForm DataGridView控件支持疊加數據綁定,或者說是附加數據功能,什么意思呢?說白了就是支持數據的多次綁定,標准的綁定方法只支持單一綁定,即每次綁定均會清除原來的數據,而疊加數據綁定則可實現每次綁定均以附加的形式(原數據保留)添加到DataGridView控件中,這樣就實現了分頁加載,但可完整顯示已加載的所有數據,這種應用場景在C/S端很常見,B/S端上也有(例如QQ空間動態下面的加載更多按鈕)

以下是實現附加數據兩種方式:

第一種方式,采用反射獲取屬性值並循環添加數據行

        private static void AppendDataToGrid(DataGridView grid, IList<object> source)
        {
            int rowCount = grid.Rows.Count;
            List<DataGridViewRow> rows = new List<DataGridViewRow>();
            Type t = source[0].GetType();
            int rowIndex = grid.Rows.Add();
            var girdCells = grid.Rows[rowIndex].Cells;
            //Common.ShowProcessing("正在加載數據,請稍候...", Common.MainForm, (o) =>
            //{
                foreach (object item in source)
                {

                    var row = new DataGridViewRow();
                    foreach (DataGridViewCell cell in girdCells)
                    {
                        var p = t.GetProperty(cell.OwningColumn.DataPropertyName);
                        object pValue = p.GetValue(item, null);
                        var newCell = (DataGridViewCell)cell.Clone();
                        newCell.Value = pValue;
                        row.Cells.Add(newCell);
                    }
                    rows.Add(row);
                }
            //});

            grid.Rows.RemoveAt(rowIndex);
            grid.Rows.AddRange(rows.ToArray());

        }

每二種方式,采用將數據源合並,然后重新綁定

        protected void AppendDataToGrid<T,TResult>(DataGridView dataGridBase, IList<T> source,Func<T,TResult> orderBy) where T : class
        {
            //Stopwatch watch = new Stopwatch();
            //watch.Start();

            if (dataGridBase.Rows.Count > 0)
            {
                IEnumerable<T> bindsource = null;
                Common.ShowProcessing("正在加載數據,請稍候...", Common.MainForm, (o) =>
                    {
                        var oldSource = (IList<T>)dataGridBase.DataSource;
                        bindsource = source.Concat(oldSource).OrderBy(orderBy).ToList();
                    });
                dataGridBase.DataSource = bindsource;
            }
            else
            {
                dataGridBase.DataSource = source;
            }

            //watch.Stop();
            //MessageBox.Show(watch.ElapsedMilliseconds.ToString());

        }

以上兩種方法在代碼量來看,第二種比較簡單,第一種在執行效率上相對第二種方法要高,原因很簡單,第一種每次處理的數據永遠都是每頁的數據,而第二種每次處理的數據是原有數據與現有數據的合集,隨着數據量越多,加載也就越慢,大家也可以試一下,當然如果大家有其它更好的方法也可以分享一下。

為了體現面向對象以及可復用性,我將上述方法變為擴展方法,完整代碼如下:

using System;
using System.Collections.Generic;
using System.Windows.Forms;
using System.Data;

namespace Zwj.Demo
{
    public interface IAppendDataAble<out TControl> where TControl : Control
    {

    }

    public class DataGridView2 : DataGridView, IAppendDataAble<DataGridView>
    {

    }

    public static class AppendDataAbleControlExtension
    {
        public static void AppendData(this DataGridView grid, dynamic dataSource)
        {
            if (!(grid is IAppendDataAble<DataGridView>))
            {
                throw new Exception("該DataGridView控件未實現IAppendDataAble<DataGridView>,無法使用該方法!");
            }

            if (dataSource.GetType().IsValueType || dataSource == null)
            {
                grid.DataSource = null;
                return;
            }

       Type interfaceType=dataSource.GetType().GetInterface("System.Collections.IList", true);
if (interfaceType!=null) {

          List<object> list = new List<object>();
          list.AddRange(dataSource);
          AppendDataToGrid(grid, list);

            }
            else if (dataSource is DataTable)
            {
                AppendDataToGrid(grid, dataSource as DataTable);
            }
        }

        /// <summary>
        /// 附加數據到DataGridView(支持IList<T>類型的數據源)
        /// </summary>
        /// <param name="grid"></param>
        /// <param name="source"></param>
        private static void AppendDataToGrid(DataGridView grid, IList<object> source)
        {
            int rowCount = grid.Rows.Count;
            List<DataGridViewRow> rows = new List<DataGridViewRow>();
            Type t = source[0].GetType();
            int rowIndex = grid.Rows.Add();
            var girdCells = grid.Rows[rowIndex].Cells;
            //Common.ShowProcessing("正在加載數據,請稍候...", Common.MainForm, (o) =>
            //{
            foreach (object item in source)
            {

                var row = new DataGridViewRow();
                foreach (DataGridViewCell cell in girdCells)
                {
                    var p = t.GetProperty(cell.OwningColumn.DataPropertyName);
                    object pValue = p.GetValue(item, null);
                    var newCell = (DataGridViewCell)cell.Clone();
                    newCell.Value = pValue;
                    row.Cells.Add(newCell);
                }
                rows.Add(row);
            }
            //});

            grid.Rows.RemoveAt(rowIndex);
            grid.Rows.AddRange(rows.ToArray());

        }

        /// <summary>
        /// 附加數據到DataGridView(支持DataTable類型的數據源)
        /// </summary>
        /// <param name="grid"></param>
        /// <param name="table"></param>
        private static void AppendDataToGrid(DataGridView grid, DataTable table)
        {
            int rowCount = grid.Rows.Count;
            List<DataGridViewRow> rows = new List<DataGridViewRow>();
            int rowIndex = grid.Rows.Add();
            var girdCells = grid.Rows[rowIndex].Cells;
            //Common.ShowProcessing("正在加載數據,請稍候...", Common.MainForm, (o) =>
            //{
            foreach (DataRow r in table.Rows)
            {
                var row = new DataGridViewRow();
                foreach (DataGridViewCell cell in girdCells)
                {
                    object pValue = r[cell.OwningColumn.DataPropertyName];
                    var newCell = (DataGridViewCell)cell.Clone();
                    newCell.Value = pValue;
                    row.Cells.Add(newCell);
                }
                rows.Add(row);
            }
            //});

            grid.Rows.RemoveAt(rowIndex);
            grid.Rows.AddRange(rows.ToArray());
        }

    }
}

對代碼稍微說明一下,為了避免擴展方法被濫用,即不需要附加數據的普通DataGridView造成影響,我定義了一個接口來規范它:IAppendDataAble<out TControl>,當然這個接口適用於所有控件,然后在擴展方法時AppendData加判斷,如果實現了IAppendDataAble接口,則表明需要用到附加數據功能,就進行后面的處理,否則報錯。我這里是基於DataGridView來擴展,大家也可以基於我定義的DataGridView2來擴展,這樣更方便。另外,我上面實現了針對兩種數據源類型進行了分別處理,以滿足大多數的情況。

方法種注釋掉的方法是我寫的顯示遮罩層的方法,如果大家需要,可以查看我的這篇博文:Winform應用程序實現通用遮罩層

 使用方法如下:

1.添加DataGridView控件,然后將DataGridView類型更改為DataGridView2類型,當然如果大家不需要進行擴展約束,那就無需更改DataGridView控件類型。

2.設置DataGridView列,將列的DataPropertyName設置為需要綁定的數據字段名稱,這步很重要。

3.然后查詢數據並調用擴展方法:

//dataGridView2Demo為DataGridView2類型
//dataSource為查詢到的數據
dataGridView2Demo.AppendData(dataSource);

 為了提高擴展方法的執行效率,降低數據源類型判斷及轉換,我們也可以選擇將擴展方法直接分為兩個擴展方法,如下:

    public static class ControlExtension
    {
        /// <summary>
        /// 附加數據到DataGridView(支持IList<T>類型的數據源)
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="grid"></param>
        /// <param name="source"></param>
        public static void AppendData<T>(this DataGridView grid, IList<T> source) where T : class
        {
            int rowCount = grid.Rows.Count;
            List<DataGridViewRow> rows = new List<DataGridViewRow>();
            Type t = typeof(T);
            int rowIndex = grid.Rows.Add();
            var girdCells = grid.Rows[rowIndex].Cells;
            Common.ShowProcessing("正在加載數據,請稍候...", Common.MainForm, (o) =>
            {
                foreach (object item in source)
                {

                    var row = new DataGridViewRow();
                    foreach (DataGridViewCell cell in girdCells)
                    {
                        var p = t.GetProperty(cell.OwningColumn.DataPropertyName);
                        object pValue = p.GetValue(item, null);
                        var newCell = (DataGridViewCell)cell.Clone();
                        newCell.Value = pValue;
                        row.Cells.Add(newCell);
                    }
                    rows.Add(row);
                }
            });

            grid.Rows.RemoveAt(rowIndex);
            grid.Rows.AddRange(rows.ToArray());

        }

        /// <summary>
        ///  附加數據到DataGridView(支持DataTable類型的數據源)
        /// </summary>
        /// <param name="grid"></param>
        /// <param name="table"></param>
        public static void AppendData(this DataGridView grid, DataTable table)
        {
            int rowCount = grid.Rows.Count;
            List<DataGridViewRow> rows = new List<DataGridViewRow>();
            int rowIndex = grid.Rows.Add();
            var girdCells = grid.Rows[rowIndex].Cells;
            Common.ShowProcessing("正在加載數據,請稍候...", Common.MainForm, (o) =>
            {
                foreach (DataRow r in table.Rows)
                {
                    var row = new DataGridViewRow();
                    foreach (DataGridViewCell cell in girdCells)
                    {
                        object pValue = r[cell.OwningColumn.DataPropertyName];
                        var newCell = (DataGridViewCell)cell.Clone();
                        newCell.Value = pValue;
                        row.Cells.Add(newCell);
                    }
                    rows.Add(row);
                }
            });

            grid.Rows.RemoveAt(rowIndex);
            grid.Rows.AddRange(rows.ToArray());
        }

    }

使用方法不變,至於用哪一種根據大家的喜好!


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM