C#TaskFactory.StartNew更改DataSource会导致System.InvalidOperationException“从另一个线程访问”

时间:2017-07-12 11:44:19

标签: c# multithreading data-binding datagridview

我目前正在构建一个依赖DataGridView通过WAMP协议接收更新的应用程序,该协议涉及处理新的消息事件。我的事件处理程序如下所示:

 private async void NewMessage(object sender, MessageEventArgs e)
 {
      await Task.Factory.StartNew(() => DataHolder.TableSource.Add(new 
      CustomData(e.Name, e.Surname, 
      e.Whatever, e.WhoTheHellCares)));
 }

当发生这样的事件时,抛出异常:System.InvalidOperationException“尝试访问在不同线程中创建的控制元素”。

DataHolder是一个静态类,它存在于具有此事件处理程序的表单类的同一名称空间中,DataHolder.TableSourceBindingList<T>,它绑定在Form.Load事件中在Form1.Designer.cs中创建的DataGridView控件。

我在这里阅读了answer相关问题,提到await能够根据需要自动将某些内容编组到UI线程,但我的狂野和无能的猜测是{{1} }无法识别数据绑定,因此必须明确告知这样做,但如何?

我需要一个.net 4.5解决方案,或证明任务和等待无法解决我的问题。 But I think they are more than able。只是我很难将它应用到我自己的情况中。

更新

哇,怎么回事..即使我的处理程序看起来像这样,它仍然给我同样的例外。

await

我想这与发起事件的类本身有关。嗯..我试过D:

更新 我使用过调试工具,这就是交易 - 事件本身已经嵌套在另一个线程中。将尝试重写我正在使用的库的源代码,以便它将支持进度报告。祝我好运D:

2 个答案:

答案 0 :(得分:1)

你误解了async / await。

您的方法将分为两部分:之前等待,之后等待。因此,当代码运行时,它将执行如下:

  1. 之前等待
  2. 在ASYNC线上徘徊
  3. 在另一个线程(不一定)
  4. 中执行等待的方法(Task.StartNew中的内容)
  5. 当第3步完成时,它将唤醒(编组)第2步的执行
  6. 在 await
  7. 之后运行

    所发生的事情是,正在编组到UI线程的是执行方法的第二部分而不是任务内部。

    除此之外还有更多,但我认为这是我用来理解它的步骤。

    要解决此问题,请完全删除异步,因为您没有进行长时间的处理:

    private void NewMessage(object sender, MessageEventArgs e)
    {
         DataHolder.TableSource.Add(new CustomData(e.Name, e.Surname, 
         e.Whatever, e.WhoTheHellCares));
    }
    

    或者如果你想要异步并且你在WinForms控件中使用BeginInvoke

    private void NewMessage(object sender, MessageEventArgs e)
    {
        this.BeginInvoke((Action)(() => DataHolder.TableSource.Add(new 
          CustomData(e.Name, e.Surname, 
          e.Whatever, e.WhoTheHellCares))));
    }
    

答案 1 :(得分:1)

  

尝试访问在不同线程中创建的控件元素

问题是你的代码正在从主UI线程以外的东西触摸UI元素(或它所依赖的东西)。 你不能这样做。

我知道您不想使用'union all',但这确实是解决此问题的方法。这些链接(和数百个类似的链接)讨论它:

根据您的评论,您可以考虑的另一种方法是Looking for .NET 4.5 Progress<T> source code。看看它如何使用SynchronizationContext。