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());
        }

    }
复制代码

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

本文转自 梦在旅途 博客园博客,原文链接:http://www.cnblogs.com/zuowj/p/4447118.html  ,如需转载请自行联系原作者

相关文章
|
2月前
|
SQL 开发框架 .NET
C#一分钟浅谈:数据绑定与数据源控件
在Web开发中,数据绑定和数据源控件是实现动态网页的关键技术。本文从基础概念入手,详细讲解数据绑定的原理及其在ASP.NET中的应用,并介绍常见数据绑定方式:手动绑定和自动绑定。接着,文章重点介绍了ASP.NET中的数据源控件,如`SqlDataSource`、`ObjectDataSource`、`XmlDataSource`和`LinqDataSource`,并通过具体示例演示如何使用`SqlDataSource`和`GridView`进行数据绑定。最后,还列举了一些常见问题及其解决办法,帮助读者更好地理解和应用这些技术。
66 4
|
4月前
|
C#
|
1月前
|
C# Python
使用wxpython开发跨平台桌面应用,对wxpython控件实现类似C#扩展函数处理的探究
【10月更文挑战第30天】使用 `wxPython` 开发跨平台桌面应用时,可以通过创建辅助类来模拟 C# 扩展函数的功能。具体步骤包括:1. 创建辅助类 `WxWidgetHelpers`;2. 在该类中定义静态方法,如 `set_button_color`;3. 在应用中调用这些方法。这种方法提高了代码的可读性和可维护性,无需修改 `wxPython` 库即可为控件添加自定义功能。但需要注意显式调用方法和避免命名冲突。
|
3月前
|
SQL API 定位技术
基于C#使用winform技术的游戏平台的实现【C#课程设计】
本文介绍了基于C#使用WinForms技术开发的游戏平台项目,包括项目结构、运行截图、实现功能、部分代码说明、数据库设计和完整代码资源。项目涵盖了登录注册、个人信息修改、游戏商城列表查看、游戏管理、用户信息管理、数据分析等功能。代码示例包括ListView和ImageList的使用、图片上传、图表插件使用和SQL工具类封装,以及高德地图天气API的调用。
基于C#使用winform技术的游戏平台的实现【C#课程设计】
|
2月前
|
设计模式 程序员 C#
C# 使用 WinForm MDI 模式管理多个子窗体程序的详细步骤
WinForm MDI 模式就像是有超能力一般,让多个子窗体井然有序地排列在一个主窗体之下,既美观又实用。不过,也要小心管理好子窗体们的生命周期哦,否则一不小心就会出现一些意想不到的小bug
125 0
|
2月前
|
API C# Windows
【C#】在winform中如何实现嵌入第三方软件窗体
【C#】在winform中如何实现嵌入第三方软件窗体
100 0
|
2月前
|
API C#
C#实现Winform程序右下角弹窗消息提示
C#实现Winform程序右下角弹窗消息提示
92 0
|
4月前
|
关系型数据库 Java MySQL
C#winform中使用SQLite数据库
C#winform中使用SQLite数据库
198 3
C#winform中使用SQLite数据库
|
4月前
|
C#
WPF/C#:数据绑定到方法
WPF/C#:数据绑定到方法
43 0
|
23天前
|
C# 开发者
C# 一分钟浅谈:Code Contracts 与契约编程
【10月更文挑战第26天】本文介绍了 C# 中的 Code Contracts,这是一个强大的工具,用于通过契约编程增强代码的健壮性和可维护性。文章从基本概念入手,详细讲解了前置条件、后置条件和对象不变量的使用方法,并通过具体代码示例进行了说明。同时,文章还探讨了常见的问题和易错点,如忘记启用静态检查、过度依赖契约和性能影响,并提供了相应的解决建议。希望读者能通过本文更好地理解和应用 Code Contracts。
31 3