我们都知道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 > )
{
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());
} }

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

C#实现WinForm DataGridView控件支持叠加数据绑定的更多相关文章

  1. Winform下让你的DataGridView控件支持点语法(即显示list中的子对象属性)

    前言: 不想看前言的直接去看正文吧!另外文末有彩蛋. DataGridView可以支持多种数据源格式,比如DataTable和List. DataTable没啥特殊的,本身就是一张二维的表,可以和Da ...

  2. winform DataGridView控件开发经验

    1.不让DataGridView控件自动生成列 设置AutoGenerateColumns 为false. dgTicket.AutoGenerateColumns = false; //将自动生成列 ...

  3. winform datagridview控件使用

    最近做项目时,显示查询结果总需要绑定到datagridview控件上显示,总结了给datagridview绑定数据的方式,以及导出datagridview数据到excel表格,如有错误请多指教 1.直 ...

  4. Winform DataGridView控件添加行号

      有很多种方法,这里介绍三种: A: 控件的RowStateChanged事件中添加,RowStateChanged事件是在行的状态更改(例如,失去或获得输入焦点)时发生的事件: e.Row.Hea ...

  5. 实现winform DataGridView控件判断滚动条是否滚动到当前已加载的数据行底部

    判断 DataGridView控件滚动条是否滚动到当前已加载的数据行底部,其实方法很简单,就是为DataGridView控件添加Scroll事件,然后写入以下代码就可以了,应用范围:可实现分部加载数据 ...

  6. winform DataGridView控件判断滚动条是否滚动到当前已加载的数据行底部 z

    http://www.zuowenjun.cn/post/2015/05/20/162.html 判断 DataGridView控件滚动条是否滚动到当前已加载的数据行底部,其实方法很简单,就是为Dat ...

  7. WinForm DataGridView控件、duck布局

    1.DataGridView控件 显示数据表 (1)后台数据绑定: List<xxx> list = new List<xxx>(); dataGridView1.DataSo ...

  8. Winform DataGridView控件在业务逻辑上的简单使用

    需要对文字列表进行处理,然后用到DataGridView控件来处理,记录一下.效果如下: 主要是想通过禁用和取消单元格选择来使图标单元格呈现出鼠标点击的效果.因为有个单元格选择的问题困扰着我. 是这样 ...

  9. Winform(DataGridView)控件及通过此控件中实现增删改查

    DataGridView:显示数据表,通过此控件中可以实现连接数据库,实现数据的增删改查 一.后台数据绑定:    List<xxx> list = new List<xxx> ...

随机推荐

  1. Xamarin 跨移动端开发系列(01) -- 搭建环境、编译、调试、部署、运行

    如果是.NET开发人员,想学习手机应用开发(Android和iOS),Xamarin 无疑是最好的选择,编写一次,即可发布到Android和iOS平台,真是利器中的利器啊!好了,废话不多说,就开始吧, ...

  2. Aoite 系列 目录

    介绍 本项目从2009年孵化(V->Sofire->Aoite),至今已度过5个年头.一直在优化,一直在重构,一直在商用.有十分完整的单元测试用例.可以放心使用. Aoite on 博客园 ...

  3. Javascrpt无刷新文件上传

    最近工作中遇到上传文件问题,主要需求是一步点击上传,兼容ie8+,当时用的dojox/form/uploader控件,这两天扒了一下源码,明白了原理拿出来分享一下. 总体思路如下: 1.对于支持XML ...

  4. 一个App完成入门篇(三)-完善主框架

    本节教程将继续带领大家完善教学demo 导入项目 完善主框架 完成viewShower子视图 打开新页 启动动画 将要学习的demo效果图如下所示 1. 如何导入完整项目 本节示例demo请参考下载地 ...

  5. Winform启动隐藏,WebBrowser交互JS

    一.启动隐藏 Winform比较奇怪,Load的时候设置Visiable=false,无效.webBrowser_DocumentCompleted之后调用hide隐藏了窗体,但是在notifyIco ...

  6. 七步,搭建基于Windows平台完美Jekyll博客环境

    最近,基于Jekyll新搭建了自己英文博客.整个过程搜索了不少资料,也尝试和过滤了不少工具和插件,最后的效果还是不错的.这里总结一下主要的七个步骤,感兴趣的朋友可以参考一下: 第一步,安装Ruby开发 ...

  7. 大叔也说Xamarin~Android篇~调用远程API接口,发POST请求

    回到目录 Xamarin我们在上节已经教大家如何去部署它的环境了,今天来说一个实际的例子,使用android客户调用.net web api的一个接口,并发送POST请求,当服务端回到请求后做出响应, ...

  8. MVVM架构~Knockoutjs系列之js接收C#数据集合的方式

    返回目录 在controller里将数据拿到,并且存储到ViewBag对象里,最后在View上显示出来,这是传统的MVC开发方式,事实上引入Knockoutjs以后,这种方式还是适合的,Knockou ...

  9. 04- Shell脚本学习--条件控制和循环语句

    条件判断:if语句 语法格式: if [ expression ] then Statement(s) to be executed if expression is true fi 注意:expre ...

  10. H5常用代码:适配方案3

    在H5项目中有一种常见的宣传页,就是那种整屏整屏的,带着炫丽进场动画的移动宣传页,不仅是一种欣赏也起到了很大宣传作用. 对于这种整屏的适配,前面通过视口的兼容处理也是可以做到的,但是在窄屏下会在上下有 ...