前言:

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

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. linux下永久添加静态路由

    在linux下永久添加静态路由有两种方法: 添加路由的命令: 1,route add route add -net 192.56.76.0 netmask 255.255.255.0 dev eth0 ...

  2. Android下的Junit测试

    Android SDK 1.5已经将JUnit包含进来了,用过一次,昨天晚上重新用的时候还出了一点问题,还是决定写一篇比较详细的文章,供大家和自己以后使用,写起来也挺方便的,Android下的Juni ...

  3. Android音乐播放-MediaPlayer

    当你坐公交无聊的时候,当你淹没在地铁中人潮中的时候,你是否想内心保持一份的安静呢,那么请带上耳机,打开你的音乐播放器,听一首老歌带你进入宁静的世界,音乐播放这个功能在智能手机出现之前,诺基亚时代,甚至 ...

  4. jquery 返回顶端组件

    自己写了一个基于jquery的返回页面顶端的组件. (function($) { var g; $.backtop = function(options) { extend($.backtop.con ...

  5. 你应该抓紧学习Python,它是开发Web应用最强大的语言

    Python和少数几种编程语言,如MySQL.Perl.PHP和与LAMP打包的网络结构一起的Apache,已经成为Linux的一个基本组件.即 使从它诞生开始,Python就与其他动态编程语言如Ru ...

  6. Android Studio 3.0 下载 使用新功能介绍

    谷歌2017发布会更新了挺多内容的,而且也发布了AndroidStudio3.0预览版,一些功能先睹为快.(英语一般,有些翻译不太好) 下载地址 https://developer.android.g ...

  7. Proguard随笔

    - ProGuard是一个压缩.优化和混淆Java字节码,它能够删除字节码中无用的类.字段.方法和无用的凝视,还能够对类.字段.方法和属性进行混淆. - 字节码事实上包括了大量的调试信息,从而非常ea ...

  8. Python编程 - json字符串的解析

    import json jsonString = '{"arrayOfNums":[{"number":0},{"number":1},{& ...

  9. Python面向对象编程 - 一个记事本程序范例(一)

    notebook.py import datetime last_id = 0 class Note: '''Represent a note in the notebook. Match again ...

  10. Linux集群监控工具简介:Ganglia和Nagios

    11年时候,曾经对 Ganglia 和 Nagios有一定接触,这是两个用于监视数据中心的工具.这两个工具被大量用于高性能计算(HPC)环境中,但是它们对于其他环境也具有很大的吸引力(例如云.呈现集群 ...