【发布时间】:2010-07-12 06:21:31
【问题描述】:
如何从另一个创建 GUI 但不在创建线程中的类更新 win 表单控件(例如标签、进度条)? (例如 Program.cs 的事件处理程序)
我发现了几篇关于使用 Invoke() 方法从另一个线程更新 GUI 的帖子,但到目前为止我发现的内容只有在代码与表单编写在同一类中时才有效
【问题讨论】:
标签: c# winforms multithreading
如何从另一个创建 GUI 但不在创建线程中的类更新 win 表单控件(例如标签、进度条)? (例如 Program.cs 的事件处理程序)
我发现了几篇关于使用 Invoke() 方法从另一个线程更新 GUI 的帖子,但到目前为止我发现的内容只有在代码与表单编写在同一类中时才有效
【问题讨论】:
标签: c# winforms multithreading
您需要在表单上调用Invoke 方法。例如:
private void someMethod() {
myOtherForm.Invoke(new MethodInvoker(delegate() {
// update things in myOtherForm here
}));
}
如果您不需要在返回方法之前完成更新,您应该使用BeginInvoke 而不是Invoke。
【讨论】:
Invoke 的委托中执行操作。具体如何操作取决于您正在编写的应用程序的结构,因此我无法为您提供任何进一步的指导。
嗯,这里有两个不同的问题:
两者几乎完全正交。单独解决每个问题后,您可以将两者放在一起。
如果有很好理解的方式需要更改 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 更可取的评论,除非你真的需要等待……尽管你确实需要小心对匿名函数捕获的任何变量的更改。)
【讨论】:
MethodInvoker 和BeginInvoke?
Control.Invoke?