前言:

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

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. 中国大学MOOC-陈越、何钦铭-数据结构-笔记

    中国大学MOOC-陈越.何钦铭-数据结构-2017春 跟着<中国大学MOOC-陈越.何钦铭-数据结构-2017春>学习,平时练习一下pat上的作业外:在这里记录一下:平时学习视屏的收获. ...

  2. Adapter 适配器模式 MD

    Markdown版本笔记 我的GitHub首页 我的博客 我的微信 我的邮箱 MyAndroidBlogs baiqiantao baiqiantao bqt20094 baiqiantao@sina ...

  3. 搭建个人博客-hexo+github

    自己也算是摸爬滚打搭建成功,然后自己再重新安装部署一遍,把完整步骤分享给大家,同时最后有一些连接,如果我的步骤不行,大家可以参考其他人的(这个有点花费时间,大家提前有个心理准备 - _-) 一.第一步 ...

  4. CSS深入了解border:利用border画三角形等图形

    三角形实际上是border的产物 我们正常使用的border都是四边一个颜色,当我们把四边换上不同颜色 那么你就会发现,三角来了~! <!DOCTYPE html> <html la ...

  5. [置顶] Android异步加载数据库和多线程编程

    Android是一种基于Linux的自由及开放源代码的操作系统,主要使用于移动设备,如智能手机和平板电脑,由Google公司和开放手机联盟领导及开发.尚未有统一中文名称,中国大陆地区较多人使用“安卓” ...

  6. LeetCode【7】.Reverse Integer--java实现

    Reverse Integer 题目要求:给定一个int 类型值,求值的反转,例如以下: Example1: x = 123, return 321      Example2: x = -123, ...

  7. java 正则表达式获得html字符串中<img src>中的src中的url地址

    public static Set<String> getImgStr(String htmlStr) { Set<String> pics = new HashSet< ...

  8. 知识共享图文直播---(一)将数据库中的数据加载到MSFlexGrid空间中再导入Excel

    熟话说万物皆有其存在的道理,为什么我突然想写<知识共享图文直播>这个系列呢?首先,我想的是记录自己学习的历程,在记录中加深自己对知识的理解,同时也希望自己的博文能帮助到其他数据库的初学者. ...

  9. 总结js(1)

    已经一个月没敲代码了,工作难找,挺烦. 先总结一下javascript吧. 1.js概述 2.语法结构 3.类型.值和变量 4.表达式和运算符 5.语句 6.对象 7.数组 8.函数 9.类和模块 1 ...

  10. 【java读书笔记】JSTL,高速精通

    JSTL并非什么新颖的技术并且非常easy,甚至有人觉得JSTL已经过时了.可是我觉得它既然存在,就有存在的道理.作为技术人员就应该知道它们是什么,怎么使用,有什么长处. JSTL包括两部分:标签库和 ...