zoukankan      html  css  js  c++  java
  • 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());
            }
    
        }

    使用方法不变,至于用哪一种根据大家的喜好!

  • 相关阅读:
    python2和python3中TestSuite().addTest的区别
    python2和python3中range的区别
    WebDriverAgent安装
    Charles IOS https抓包
    Python和 pytest的异常处理
    Python中yaml和json文件的读取和应用
    Python 获取当前文件所在路径
    自建包函数调用
    python的logging,将log保存到文件
    泛型
  • 原文地址:https://www.cnblogs.com/zuowj/p/4447118.html
Copyright © 2011-2022 走看看