我目前正在构建一个依赖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.TableSource
是BindingList<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:
答案 0 :(得分:1)
你误解了async / await。
您的方法将分为两部分:之前等待,之后等待。因此,当代码运行时,它将执行如下:
所发生的事情是,正在编组到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。