前言:

不想看前言的直接去看正文吧!另外文末有彩蛋。

DataGridView可以支持多种数据源格式,比如DataTable和List。

DataTable没啥特殊的,本身就是一张二维的表,可以和DataGridView行列对应。

但是List不太一样,举个栗子,有一个UserList用户列表,格式是这样的:

class UserModel{
Id
Name,
Gender,
Age,
JobModel
} class JobModel{
JobId,
JobName,
UserId
}

对于上面这种,User中带有一个Job实体的数据结构,Job类中的三个属性在DataGridView中是无法直接显示的。

于是你想当然地会在DataGridView中这样绑定:JobModel.JobName

但是,现实是很骨感的:

工作名称那一栏并没有被匹配到,在最右侧则有一个JobModel的实例则直接被显示了出来。

这显然不是我们想要的结果。

所以,我们要做的就是让DataGridView支持点语法。

那么正文开始!

正文:

好吧,其实正文真的很简单。

只要在DataGridView控件的CellFormatting事件中加入以下代码即可。

其中dgvLinqDemo改成你自己的控件名就好啦:

if ((dgvLinqDemo.Rows[e.RowIndex].DataBoundItem != null) &&
(dgvLinqDemo.Columns[e.ColumnIndex].DataPropertyName.Contains(".")))
{
string[] nameAndProp = dgvLinqDemo.Columns[e.ColumnIndex].DataPropertyName.Split(new char[] { '.' });
object pObj = dgvLinqDemo.Rows[e.RowIndex].DataBoundItem;
for (int i = ; i < nameAndProp.Length - ; i++)
{
pObj = GetObject(pObj, nameAndProp[i]);
if (pObj == null)
{
e.Value = string.Empty;
break;
}
if (i == nameAndProp.Length - )
{
PropertyInfo objectProperty = pObj.GetType().GetProperty(nameAndProp[i + ]);
e.Value = objectProperty.GetValue(pObj, null).ToString();
}
}
} private object GetObject(object pObj, string nameAndProp)
{
if (pObj == null)
{
return null;
}
PropertyInfo objProp = pObj.GetType().GetProperty(nameAndProp);
return objProp.GetValue(pObj, null);
}

后话:

正文讲完了,如果你想知道原理的话,可以看我下面的大篇幅的注释说明。

大致的思路是通过拆分点语法的字符串来通过反射获取下一级的对象或值。

 //CellFormatting中的代码
if ((dgvLinqDemo.Rows[e.RowIndex].DataBoundItem != null) &&
(dgvLinqDemo.Columns[e.ColumnIndex].DataPropertyName.Contains(".")))
{
//对具有点语法的字段进行分割
//比如JobModel.SkillModel.SkillName
//分割成JobModel,SkillModel和SkillName
string[] nameAndProp = dgvLinqDemo.Columns[e.ColumnIndex].DataPropertyName.Split(new char[] { '.' }); object pObj = dgvLinqDemo.Rows[e.RowIndex].DataBoundItem;
//i<nameAndProp.Length-1是因为,只需要循环属性名长度-1次就可以了。
//比如,对于JobModel.JobName,在上一步中已经获取了JobModel实体
//那么在for循环中的代码只需要执行一遍,即i<nameAndProp.Length-1次,即可获取JobName的属性
for (int i = ; i < nameAndProp.Length - ; i++)
{
pObj = GetObject(pObj, nameAndProp[i]);
//以JobModel.JobName为例,它只在i=0的时候进来执行一次并获取属性值
//那么这里就只能为nameAndProp.Length - 2才能顺利获取到属性值
if (i == nameAndProp.Length - )
{
//下面代码中的i+1可以保证它获取的是最后的属性值
//即:JobModel.JobName的时候取的是JobName的值
//或者JobModel.SkillModel.SkillName的时候取得是SkillName的值
PropertyInfo objectProperty = pObj.GetType().GetProperty(nameAndProp[i + ]);
e.Value = objectProperty.GetValue(pObj, null).ToString();//取出字段值
}
}
} /// <summary>
/// 通过当前对象和子属性名来获取子对象的实例
/// 比如传入UserModel对象和"JobModel"字符串来获取JobModel的实例
/// </summary>
/// <param name="pObj"></param>
/// <param name="nameAndProp"></param>
/// <returns></returns>
private object GetObject(object pObj, string nameAndProp)
{
if (pObj == null)
{
return null;
}
PropertyInfo objProp = pObj.GetType().GetProperty(nameAndProp);
return objProp.GetValue(pObj, null);
}

优化:

讲解讲完了,原理也懂了。

但是你发现如果你有好多个DataGridView,就需要写好多CellFormatting代码。

有一百个DataGridView就要写一百次!这显然太蠢了!

所以我们把这些支持点语法的代码封装成一个新的控件。

这样我们只要直接把自定义的控件拖进Winform界面就可以不写任何一行代码就能直接使用点语法啦!

1.创建类库,就像这样:

2.为DataGridViewPro项目添加引用,就像这样:

3.将自动创建的class1.cs改名为DataGridViewPro.cs,然后代码写成样:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Windows.Forms; namespace DataGridViewPro
{
public class DataGridViewPro : DataGridView
{
public DataGridViewPro()
{
InitializeComponent();
} private void InitializeComponent()
{
this.CellFormatting += CellFormattingPro;
} private void CellFormattingPro(object sender, DataGridViewCellFormattingEventArgs e)
{
if ((this.Rows[e.RowIndex].DataBoundItem != null) &&
(this.Columns[e.ColumnIndex].DataPropertyName.Contains(".")))
{
string[] nameAndProp = this.Columns[e.ColumnIndex].DataPropertyName.Split(new char[] { '.' });
object pObj = this.Rows[e.RowIndex].DataBoundItem;
for (int i = ; i < nameAndProp.Length - ; i++)
{
pObj = GetObject(pObj, nameAndProp[i]);
if (pObj == null)
{
e.Value = string.Empty;
break;
}
if (i == nameAndProp.Length - )
{
PropertyInfo objectProperty = pObj.GetType().GetProperty(nameAndProp[i + ]);
e.Value = objectProperty.GetValue(pObj, null).ToString();
}
}
}
} private object GetObject(object pObj, string nameAndProp)
{
if (pObj == null)
{
return null;
}
PropertyInfo objProp = pObj.GetType().GetProperty(nameAndProp);
return objProp.GetValue(pObj, null);
}
}
}

ok,大功告成,把它编译成dll放入你的项目里直接使用带有点语法特性的DataGridViewPro吧!

最后,放上我亲手制作的彩蛋DataGridViewPro.dll,下载引入项目即刻使用!

参考链接:

WinForm创建自定义控件

为C#自定义控件添加自定义事件

如何重写自定义控件里的事件

Winform下让你的DataGridView控件支持点语法(即显示list中的子对象属性)的更多相关文章

  1. C#实现WinForm DataGridView控件支持叠加数据绑定

    我们都知道WinForm DataGridView控件支持数据绑定,使用方法很简单,只需将DataSource属性指定到相应的数据源即可,但需注意数据源必须支持IListSource类型,这里说的是支 ...

  2. winform窗体(六)——DataGridView控件及通过此控件中实现增删改查

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

  3. c# WinForm开发 DataGridView控件的各种操作总结(单元格操作,属性设置)

    一.单元格内容的操作 *****// 取得当前单元格内容 Console.WriteLine(DataGridView1.CurrentCell.Value); // 取得当前单元格的列 Index ...

  4. 转:c# WinForm开发 DataGridView控件的各种操作总结(单元格操作,属性设置)

    一.单元格内容的操作 *****// 取得当前单元格内容 Console.WriteLine(DataGridView1.CurrentCell.Value); // 取得当前单元格的列 Index  ...

  5. Android自己定义控件而且使其能够在xml中自己定义属性

    为什么要自己定义View android开发中自己定义View的优点是显而易见的.比方说以下的这个顶部导航,它被设计出如今应用的每一个界面,但每次的内容却不尽同样.我们不能在每一个layout资源中都 ...

  6. DataGridView控件

    DataGridView控件 DataGridView是用于Windows Froms 2.0的新网格控件.它可以取代先前版本中DataGrid控件,它易于使用并高度可定制,支持很多我们的用户需要的特 ...

  7. DataGridView控件-[引用]

    DataGridView控件 DataGridView是用于Windows Froms 2.0的新网格控件.它可以取代先前版本中DataGrid控件,它易于使用并高度可定制,支持很多我们的用户需要的特 ...

  8. DataGridView控件使用大全说明-各种常用操作与高级操作

    DataGridView控件 DataGridView是用于Windows Froms 2.0的新网格控件.它可以取代先前版本中DataGrid控件,它易于使用并高度可定制,支持很多我们的用户需要的特 ...

  9. DataGridView控件使用大全

    转自:http://www.cnblogs.com/xiaofengfeng/archive/2011/04/16/2018504.html DataGridView控件 DataGridView是用 ...

随机推荐

  1. Objective-C:内存管理的小结

    内存管理: 1.OC的对象都是分配在堆里的      Perosn *person  = [[Person alloc]init];      Person *person       //指针类型的 ...

  2. 第二章 Jackson属性名转换+属性忽略

    @Data @JsonIgnoreProperties(ignoreUnknown = true) public class MyRecord { private boolean succeed; p ...

  3. nginx 域名绑定 域名, nginx 域名绑定 端口

    一.nginx 域名绑定 域名 nginx绑定多个域名可又把多个域名规则写一个配置文件里,也可又分别建立多个域名配置文件,我一般为了管理方便,每个域名建一个文件,有些同类域名也可又写在一个总的配置文件 ...

  4. JSP简单练习-定时刷新页面

    <%@ page contentType="text/html; charset=gb2312" %> <%@ page import="java.ut ...

  5. qt creator修改程序编码(解决中文乱码问题)的方法

    qt creator修改程序编码(解决中文乱码问题)的方法 qt creator修改程序编码的功能有几处. 1.edit - select encoding 选择载入(显示)编码和储存编码,其中GB2 ...

  6. BZOJ 3172 Tjoi2013 单词 后缀数组

    题目大意:给定一个n个单词的文章,求每一个单词在文章中的出现次数 文章长度<=10^6(不是单词长度<=10^6,不然读入直接超时) 首先将全部单词用空格连接成一个字符串.记录每一个单词的 ...

  7. 翻译记忆软件-塔多思TRADO经典教程_4

    SDL Trados是世界上最流行的计算机辅助翻译(CAT) 软件,在全球拥有20万多客户,全球500强企业有超过90%的公司都在使用SDL Trados来为日常的本地化翻译工作服务.我们的使命是以强 ...

  8. GP开发示例:数据库去重

    这个例子专业讲解基于ArcEngine使用GP开发的过程及遇到的问题.更多GP使用方法:GP使用心得 功能需求:现在外业第一次数据(简称调绘.mdb)和第二次数据(简称检查.mdb)有重复.第二次是在 ...

  9. Session 共享(StateServer模式)(原创)

    Session 共享要注意两点: 1.必须在同一个域名下 2.StateServer模式是把session保存在同一台服务器上的进程:aspnet_state.exe里面,当然也可以保存在memcac ...

  10. Java从零开始学四十(反射简述一)

    一.JAVA是动态语言吗? 一般而言,说到动态言,都是指在程序运行时允许改变程序结构或者变量类型,从这个观点看,JAVA和C++一样,都不是动态语言. 但JAVA它却有着一个非常突出的动态相关机制:反 ...