关于DataGridView的使用注意事项

写在前面

在日常使用DataGridView时,大多数情况下用起来都特别简单,但偶尔遇到一些坑时也会折磨人很久。现在编写此篇博客, 以记录在平时工作时遇到的一些坑。

场景1:DataGridView的CellFormatting事件

因为业务需要,我的DataGridView绑定的数据源中,有个列不在DataSource绑定的对象里,这时就需要增加自定义列,同时也需要自己编写展示自定义列的数据的处理,于是我就对这个列增加了CellFormatting事件。最初的时候,我编写的代码如下,结果发现我原本DataSource绑定的对象中的任意一个列,一旦有null值,就会报DataFormatted错误,我百思不得其解,最后才发现,我把这个e.FormattingApplied写在了CellFormatting事件方法的最外面,如下代码所示:

// 错误示例

private void DGV_CellFormatting(object sender, DataGridViewCellFormattingEventArgs e)
{
    if (e.ColumnIndex == dgv.Columns["attr1"].Index)
    {
                
        // 业务逻辑
        if(xxx){
            e.Value = xxx.ToString();
        }
        else{
            e.Value = string.Empty;
        }
        
    }
    

    e.FormattingApplied = true;    // 致命错误
}

正确的应该是这么写:

// 改正之后

private void DGV_CellFormatting(object sender, DataGridViewCellFormattingEventArgs e)
{
    if (e.ColumnIndex == dgv.Columns["attr1"].Index)
    {
                
        // 业务逻辑
        if(xxx){
            e.Value = xxx.ToString();
        }
        else{
            e.Value = string.Empty;
        }
        e.FormattingApplied = true;    // 此行代码如果放至最外层,会对DataGridView的每一个列都进行格式化
    }
    
}

原因:把e.FormattingApplied=true写在最外层,就会导致数据源所有的列都会生效,这时候一旦你数据源中的某个列有null值,就会报异常。而放在if内部,则只会对这单个列生效。(还是不能过于省代码)

场景2:DataGridView的数据源中含有嵌套对象如何显示列

这个场景简单介绍一下:就是我的DataGridView的DataSource绑定到了一个List<MyParentObj>,然后,MyParentObj内部,还定义了一个子对象MySubObj,现在,我需要将MySubObj的字段展示到DataGridView,而默认绑定的情况下,DataGridView只能识别到MyParentObj中个各种基本类型的列,比如MyParentObj中有个string类型的steelName,那么当你通过myDataGridView.DataSource = myParentObjs的方式进行绑定后,可以直接通过myDataGridView.Columns["steelName"].XXX的方式,直接对该属性进行展示列的相关设置。但是,却无法通过这种方式来操作MySubObj的任一属性。后面我在网上找了几种办法,然后发现了一种比较简单但是不优雅的方式,那就是在MyParentObj中,再定义几个字段,这些字段就是用来访问MySubObj中的各个元素。举个例子,我们需要在DataGridView中展示MySubObj中的furName属性,在MyParentObj中定义一个属性mySubObj,该属性的get方法即返回MySubObj的furName,默认的类定义代码如下:

public class MyParentObj {
    public string steelName
    {
        get;
        set;
    }

    public MySubObj mySubObj;
    {
        get;
        set;
    }
}

public class MySubObj 
{
    public string furName 
    {
        get;
        set;
    }
}

增加访问子类furName之后的类定义如下:

public class MyParentObj {
    public string steelName
    {
        get;
        set;
    }

    public MySubObj mySubObj;
    {
        get;
        set;
    }
    // 新增的mySubObjFurName属性用于访问子类的成员
    public string mySubObjFurName
    {
        get
        {
            if (mySubObj != null && mySubObj.furName != null)
            {
                return mySubObj.furName;
            }
            return "";
        }
        set
        {
            mySubObj.furName = value;
        }
    }
}

public class MySubObj 
{
    public string furName 
    {
        get;
        set;
    }
}

对类增加对应的属性后,就可以直接使用myDataGridView.Columns["mySubObjFurName"].XXX的方式,来对furName属性进行访问了。(当然了,不到万不得已,尽量不要使用这种方式)

场景3:基于场景1对列进行了CellFormatting事件之后,通过dataGridView.Rows[i].Cells[j].Value的方式来获取该单元格的值,结果为null

在通过场景1的方式,将自定义的列展示出来之后,我后面需要再其他地方来获取这些自定义列的值,最初是通过调用dataGridView.Rows[i].Cells[j].Value的方式来获取,在调试时我发现结果均为null(注意是结果为null,不是默认值),通过查阅相关资料均为发现问题原因,后面通过询问ChatGPT,给我一个可能的答案,居然还真是的!然后我就把场景1的CellFormatting事件代码做了如下修改:

// 改正之后

private void DGV_CellFormatting(object sender, DataGridViewCellFormattingEventArgs e)
{
    if (e.ColumnIndex == dgv.Columns["attr1"].Index)
    {
                
        // 业务逻辑
        if(xxx){
            e.Value = xxx.ToString();
            row.Cells[e.ColumnIndex].Value = e.Value;        // 增加该行
        }
        else{
            e.Value = string.Empty;
        }
        e.FormattingApplied = true;    // 此行代码如果放至最外层,会对DataGridView的每一个列都进行格式化
    }
    
}

相较于场景1,只增加了一句:row.Cells[e.ColumnIndex].Value = e.Value; 这一行表示是对该单元格赋值,而e.Value = xxx.ToString(); 仅仅只是展示数据,并不会对该行赋值!

其他场景等后续更新

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

CodemanNotColdman

谢谢您给予我创作下去的动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值