如何从另一个类更新Windows窗体GUI?
如何从创建GUI而不是创建线程的另一个类更新win表单控件(例如标签,进度条)? (例如,Program.cs的事件处理程序)
我发现了几篇关于使用Invoke()方法从另一个线程更新GUI的post,但到目前为止我发现的只有在代码与表单编写在同一个类中时才有效
http://www.yoda.arachsys.com/csharp/threads/winforms.shtml
您需要在窗体上Invoke
方法。 例如:
private void someMethod() { myOtherForm.Invoke(new MethodInvoker(delegate() { // update things in myOtherForm here })); }
如果在返回方法之前不需要完成更新,则应使用BeginInvoke
而不是Invoke
。
那么,这里有两个不同的问题:
- 从其他类更新UI
- 从其他线程更新UI
这两者几乎完全正交。 一旦你孤立地解决了每一个问题,你就可以将两者结合起来。
如果有很好理解的方式需要更改UI(例如更新状态栏中的文本或类似的东西),我会在UI类本身中编写方法来执行此操作,并从另一个中调用这些方法类。 或者,您可以公开UI的各个控件 – 最好通过属性 – 然后以正常方式从其他类使用Control.Invoke
,例如
MethodInvoker action = () => form.StatusLabel.Text = "Finished"; form.BeginInvoke(action);
只要你在一个控件上调用Invoke
,它与你触摸的所有控件都存在于同一个线程上,那么你使用哪个控件并不重要…所以另一个选择可能是:
Label label = form.StatusLabel; MethodInvoker action = () => label.Text = "Finished"; label.BeginInvoke(action);
这里的一个区别是,在后面的代码中, StatusLabel
属性正在工作线程中进行评估 – 如果您的UI正在更改它以在不同时间引用不同的标签,则可能导致竞争条件。 我通常更喜欢第一种方法。
(我同意icktoofay关于BeginInvoke
的评论是优选的,除非你真的需要等待,顺便说一下……虽然你需要注意对匿名函数捕获的任何变量的更改。)