2009-03-05 130 views
0

好的,请忽略之前的情况。我再也没有收到错误,所以看起来我的问题是,当我更改图表数据绑定的值时,需要更新图表。Control.Refresh()跨线程

//以下无视

大家好。我有一个WinForms应用程序,它有一个面板,panel1。后台线程创建,然后被添加到panel1像这样

panel1.Controls.AddRange(myArrayOfControls); 

这个伟大的工程,我可以看到我的控制得到补充一些其他控件。但是,当新数据进入另一个线程时,我更新控件父对象中的值,然后需要Refresh()以使显示更新为新值。在上下文中调用Refresh(),数据进入的线程或接收更新数据的对象都会导致InvalidOperation异常,因为需要调用Invoke。我已经尝试在我的模型对象中使用Invoke,也尝试在数据传入并且看起来无法动摇错误的线程中使用Invoke。

如果有人有一些指导,我将不胜感激。

更新:这里有一些更多的信息。我不认为这需要它,但我错了。 :)

我有一个对象类MyObject。这个MyObject类是在一个名为topologyThread的线程中创建的。数据来自dataThread。 MyObject的实例具有一个Panel实例变量,并且Panel有子控件,包括来自System.Windows.Forms.DataVisualization.Charting命名空间的两个图表。因此,随着数据进入dataThread,我更新MyObject对象中的相应数据值,然后需要刷新图表以显示更新的数据。

我知道数据处理得很好。在MyObject类中,我将新值记录到属性的setter中的Console,并看到新值显示。

回答

6

您必须从主UI线程执行两个操作(刷新和更新控件的父对象)。如果你正在从后台线程修改一个控件而没有得到一个不幸的异常,因为这肯定是一个错误。

要做到这一点,最好的办法是使用

theControl.Invoke(new MethodInvoker(MyUpdateMethod)); 

如果你的更新是如何完成的样本,我们可以就如何正确地从后台线程调用它一个更好的样品。

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)); 
1

JaredPar是一个很好的答案。我想补充一点你的代码排序的原因。

使用Windows窗体,您可以从其他线程与UI线程交谈。在所有情况下这都是非常糟糕的做法。

问题是,当你这样做的时候,很难抓住,因为有时UI会像没有错误一样工作。项目将被添加或更改,UI将反映更改。但其他时间运行相同的确切代码,它不会工作。

这是从任何其他线程接触用户界面的方式。输出是不一致的,这就是为什么非常糟糕的做法。

上帝,我希望我能发表评论。 :)

+1

+1,现在你10代表更接近能够评论。 :) – 2009-03-05 19:38:35