好的,请忽略之前的事情。我不再得到错误了,所以看起来我的问题是当我更改图表数据绑定的值时更新图表。
//忽视这里
大家好。我有一个WinForms应用程序,它有一个面板,panel1
。后台线程会创建一些其他控件,然后像{<1>}一样添加到panel1
panel1.Controls.AddRange(myArrayOfControls);
这很好用,我可以看到我的控件被添加了。但是,当新数据进入另一个线程时,我更新控件的父对象中的值,然后需要Refresh()
以使用新值更新显示。在任一上下文中调用Refresh()
,数据进入的线程或接收更新数据的对象都会导致InvalidOperation异常,因为需要Invoke。我已经尝试在我的模型对象中使用Invoke以及数据传入的线程,但似乎无法动摇错误。
如果有人有一些指导我会非常感激。
更新:这里有更多信息。我不认为它需要它,但我错了。 :)
我有一个对象类MyObject。此MyObject类在名为topologyThread的线程中创建。数据来自dataThread。 MyObject的实例具有Panel实例变量,Panel具有子控件,包括System.Windows.Forms.DataVisualization.Charting命名空间中的两个Charts。因此,当数据进入dataThread时,我更新MyObject对象中的相应数据值,然后需要刷新图表以显示更新的数据。
我知道数据处理正常。在我的MyObject类中,我在属性的setter中将新值记录到Console,并看到新值显示。
答案 0 :(得分:6)
您必须从主UI线程执行这两项操作(刷新和更新控件的父对象)。如果您正在从后台线程修改控件而没有得到运气不好的异常,因为它肯定是一个错误。
最好的方法是使用
theControl.Invoke(new MethodInvoker(MyUpdateMethod));
如果您有更新完成方式的示例,我们可以提供一个更好的示例,说明如何从后台线程正确调用它。
答案 1 :(得分:1)
JaredPar是一个非常好的答案。我想补充一下你的代码有效的原因。
使用Windows窗体,您可以与其他线程的UI线程通信。在所有情况下,这都是不好的做法。
问题在于,当你这样做时,它很难被捕获,因为有时UI会像没有错误一样工作。项目将被添加或更改,UI将反映更改。但是其他时候运行相同的确切代码,它将无法正常工作。
这是从UI线程以外的任何线程触摸UI的问题。出来是不一致的,这就是为什么非常糟糕的做法。
上帝,我希望我能发表评论。 :)
答案 2 :(得分:0)
JaredPar的回答很好。它可能会在某些情况下导致问题(特别是在构造完成表单之前调用该方法时)。这是一个更强大的实现(使用扩展方法)
public static class ControlInvokeExtensions
{
public static void InvokeOnHostThread(Control host, MethodInvoker method)
{
if (IsHandleCreated)
Invoke(new EventHandler(delegate { method(); }));
else
method();
}
}
现在你可以这样称呼它
panel1.InvokeOnHostThread(() => panel1.Controls.AddRange(myArrayOfControls));
或者如果你的形式是:
InvokeOnHostThread(() => panel1.Controls.AddRange(myArrayOfControls));