【问题标题】:C# Cannot access a disposed object when adding rows asynchronously to a winform datagridview将行异步添加到winform datagridview时,C#无法访问已释放的对象
【发布时间】:2017-11-17 23:24:33
【问题描述】:

我正在使用以下代码从并行线程将文档加载到 datagridview 中: 在块内Task.Run(() => {});

当我关闭表单时,我得到 ObjectDisposedException Cannot access a disposed object. 看起来 if (IsDisposed || Disposing) 失败并且代码尝试添加一行,同时 Disposing 已变为 true。

我可以捕捉到这个异常,但它很脏。

在关闭表单时添加启用标志以检查表单是否已关闭也不起作用。它的行为方式似乎与this.Disposing

if (this.IsDisposed || this.Disposing) 之前添加Thread.Sleep(5); 似乎足以避免引发异常,但我不确定如果运气不好是否可以引发异常。

避免此问题的最佳做法可能是什么?

  foreach (var doc in docList)
  {
     if (this.InvokeRequired)
     {
         if (IsDisposed || Disposing || dgv.IsDisposed || dgv.isposing) return;
         this.Invoke(new MethodInvoker(() => { dgv.Rows.Add(doc.Name); }));
     }
  }

【问题讨论】:

  • 也许你只是想隐藏表单?
  • 您不会将行异步添加到网格视图中。您不能将行异步添加到 gridview 或任何其他 UI 元素。 Invoke 表示“在 UI 线程上运行”。这段代码只是浪费了一个后台线程,在 UI 线程上以最慢的方式添加行,每次添加行时都强制重绘。
  • 您应该删除此代码的全部,并将gridview 绑定到包含数据的集合或数据表。到底有多少数据?人类不能一次看到 100 行,你也不能显示它们。如果您有大量数据,请使用分页和虚拟滚动来仅加载需要的内容
  • 此外,不要使用async void,除非在事件处理程序中。不返回结果的异步方法的签名是async Task。你不能等待、停止或处理任何以async void运行的东西
  • 您的实际问题是什么?你为什么要“异步加载网格”?你遇到性能问题了吗?您是否在消息到达后立即添加消息?您是否试图一次显示太多东西?还有什么?不管它是什么,自从 15 年前 .NET 1.0 出现以来,就有一些技术可以处理它。没有涉及async

标签: c# winforms async-await task objectdisposedexception


【解决方案1】:

不知道关闭后要对表单做什么。如果可以隐藏它,请使用:

private void MyForm_FormClosing(object sender, FormClosingEventArgs e)
    {
        e.Cancel = true;
        this.Hide();
    }

【讨论】:

  • 我不想使用不必要的资源。为什么不关闭表单?
【解决方案2】:

您是否尝试过在 Invoke 中添加条件:

if (this.InvokeRequired)
{
    this.Invoke(new MethodInvoker(() => 
    {
        foreach (var doc in docList)
        {
            if (IsDisposed || Disposing || dgv.IsDisposed || dgv.isposing)  return;
            dgv.Rows.Add(doc.Name); 
        }));
    }
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-01-02
    • 2016-12-06
    相关资源
    最近更新 更多