【问题标题】:Refreshing DataGridView bindings to a list when a row is deleted删除行时刷新 DataGridView 绑定到列表
【发布时间】:2010-11-28 23:02:31
【问题描述】:

我有一个 WinForm 应用程序,其中有多个绑定到 SortableBindingLists 的 DataGridView。

在某些情况下,我需要以编程方式从网格绑定到的列表中删除一个项目。

我似乎无法让 DGV 识别它的数据已更改,或者具体来说,它的行数减少了。我正在调用 dataGridView1.Invalidate(),它正在重新绘制网格,但它尝试重新绘制与以前一样多的行,并引发一系列“索引不存在”的异常,每一列都有一个异常。

这是一个展示问题的简化代码示例:(只是一个带有 DGV 和一个按钮的 WinForm。)

    private List<Employee> list;
    private void Form1_Load(object sender, EventArgs e)
    {
        list = new List<Employee>();
        for (int ix = 0; ix < 3; ix++)
        {
            list.Add(ObjectMother.GetEmployee(ix+1));
        }

        dataGridView1.DataSource = list;
    }

    private void cmdDeleteARow_Click(object sender, EventArgs e)
    {
        list.Remove(list[0]);
        dataGridView1.Invalidate();

    }

在 ASP.NET 中,当使用 GridView 控件时,可以调用“DataBind()”方法来强制它刷新数据。 WinForms 中似乎没有这样的东西,还是我遗漏了什么?

【问题讨论】:

    标签: winforms datagridview data-binding


    【解决方案1】:

    试试

    dataGridView1.Refresh()
    

    【讨论】:

    • 谢谢,迈克尔,但它给出了相同的结果。我尝试用 Refresh 替换 Invalidate 调用,还尝试将 Invalidate 保留在其中并在之前和之后添加 Refresh。仍然抛出相同的异常。
    【解决方案2】:

    好吧,既然我没有得到任何有用的回复,我将继续使用我想出的工具。

    如果您使用反射进入 DataGridView.DataSource 属性,您将看到绑定方法仅在 DataSource 更改时才被调用。请注意,对 DataSource 内容的更改(例如,添加、更改或删除列表元素)不会被识别为对 DataSource 的更改。为了强制调用数据绑定方法,我成功地将 DataSource 重新分配给其他对象,然后将其分配回列表。看起来非常笨拙,并且极大地浪费了 CPU 周期,但它似乎有效。于是代码变成了:

        private void cmdDeleteARow_Click(object sender, EventArgs e)
        {
            list.Remove(list[0]);
            dataGridView1.DataSource = new List<Employee>();
            dataGridView1.DataSource = list;
            dataGridView1.Invalidate();
        }
    

    如果有人有更好的想法(我相信肯定有一些),请告诉我。

    【讨论】:

    • 我遇到了和你一样的错误,我的情况是一样的,即在 for 循环中读取 datadridview 的数据并对每一行进行一些操作,最后删除当前行...所以我所做的是创建了一个委托函数来删除它,因为我正在使用后台工作线程......它适用于...... ru 使用 ne 后台线程
    • Andrew Watt 发布了一个非常好的答案。你的既不是答案也不是好的。请在 Andrew 的帖子上打勾。
    【解决方案3】:

    为了让DataGridView 了解对其DataSource 的更改,源应实现IBindingListList&lt;T&gt; 没有,因此它不会广播其更改,DataGridView 不知道它需要更新。

    在这种情况下,一个简单的解决方法是在列表和DataGridView 之间放置一个BindingSource,然后在其上调用Remove()

    private List<Employee> list;
    private BindingSource bindingSource;
    private void Form1_Load(object sender, EventArgs e)
    {
        list = new List<Employee>();
        for (int ix = 0; ix < 3; ix++)
        {
            list.Add(ObjectMother.GetEmployee(ix+1));
        }
    
        dataGridView1.DataSource = bindingSource;
        bindingSource.DataSource = list;
    }
    
    private void cmdDeleteARow_Click(object sender, EventArgs e)
    {
        bindingSoruce.Remove(list[0]); // or, RemoveAt(0)
    
        // Probably not necessary:
        // dataGridView1.Invalidate();
    }
    

    或者,您可以使用BindingList&lt;T&gt; 代替List&lt;T&gt;,或者创建自己的列表类来实现IBindingList

    【讨论】:

    • 这是超级旧的,但它接近谷歌的顶部,所以我会在这里扔一些东西。切换到 BindingList 100% 效果很好。其次,我发现了一些事情,如果您使用 bindingsource 方式,如果您在原始列表上运行 add/removes,您将不会看到 DataGridView 上反映的更改。您需要在绑定源上运行添加/删除。
    【解决方案4】:

    我尝试过使用容器对象的 Validate() 方法,它在同步数据网格视图和绑定数据表时运行良好。

    Visual C++ 中的一个例子可以这样给出:

    // 假设 dgv 已经在代码中创建为 Data Grid View 对象

    SplitContainer^ dgvContainer = dynamic_cast(dgv->Parent->Parent); dgvContainer ->Validate();

    希望对你有帮助。

    【讨论】:

      猜你喜欢
      • 2020-10-30
      • 1970-01-01
      • 2010-12-06
      • 1970-01-01
      • 2019-09-17
      • 1970-01-01
      • 2011-03-21
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多