如何从另一个类更新Windows窗体GUI?

Lou*_*hys 4 c# multithreading winforms

你如何从另一个创建GUI而不是创建线程的类更新win表单控件(例如标签,进度条)?(例如,Program.cs的事件处理程序)

我发现了几个关于使用Invoke()方法从另一个线程更新GUI的帖子,但到目前为止我发现的只有在代码与表单编写在同一个类中时才有效

http://www.yoda.arachsys.com/csharp/threads/winforms.shtml

ick*_*fay 8

您需要Invoke在表单上调用该方法.例如:

private void someMethod() {
    myOtherForm.Invoke(new MethodInvoker(delegate() {
        // update things in myOtherForm here
    }));
}
Run Code Online (Sandbox Code Playgroud)

如果在返回方法之前不需要完成更新,则应使用BeginInvoke而不是Invoke.


Jon*_*eet 6

那么,这里有两个不同的问题:

  • 从其他类更新UI
  • 从其他线程更新UI

这两者几乎是完全正交的.一旦你孤立地解决了每一个问题,你就可以将两者结合起来.

如果有很好理解的方式需要更改UI(例如更新状态栏中的文本或类似的东西),我会在UI类本身中编写方法来执行此操作,并从其他方法中调用这些方法类.或者,您可以公开UI的各个控件 - 最好通过属性 - 然后Control.Invoke以正常方式使用其他类,例如

MethodInvoker action = () => form.StatusLabel.Text = "Finished";
form.BeginInvoke(action);
Run Code Online (Sandbox Code Playgroud)

只要你调用Invoke一个与你触摸的所有控件"生活"在同一个线程上的控件,你使用哪个控件都没关系...所以另一个选择可能是:

Label label = form.StatusLabel;
MethodInvoker action = () => label.Text = "Finished";
label.BeginInvoke(action);
Run Code Online (Sandbox Code Playgroud)

这里的一个区别是,在后面的代码中,StatusLabel属性正在工作线程中进行评估 - 如果您的UI正在更改它以在不同时间引用不同的标签,则可能导致竞争条件.我通常更喜欢第一种方法.

(我同意icktoofay关于BeginInvoke更好的评论,除非你真的需要等待,顺便说一下......虽然你需要注意对匿名函数捕获的任何变量的更改.)