WinForms线程间修改
Posted
技术标签:
【中文标题】WinForms线程间修改【英文标题】:WinForms interthread modification 【发布时间】:2009-07-10 15:59:57 【问题描述】:每当我想从另一个线程修改一个winform时,我都需要使用
->Invoke(delegate, params)
以便修改发生在winform自己的线程中。
对于每个需要修改 gui 的函数,我都需要另一个委托函数。
是否有一些方案可以让我限制所需的委托函数的数量?我有一个控制器类,可以在一个地方处理整个 gui,我曾考虑过重用委托,但味道很糟糕。
我认为我的问题可以适用于所有可以运行 winform 的语言
【问题讨论】:
【参考方案1】:如果您使用的是 C# 3,则可以使用 lambda,而在 C# 2 中,可以使用匿名委托。当不需要重用行为时,这些简化了语法。我总是做的一件事是在表单代码中进行同步,而不是在控制器中。控制器不应该被这类“管道”问题所困扰,这些问题更具体于技术而不是控制器逻辑。
public void ResetFields()
// use "delegate" instead of "() =>" if .Net version < 3.5
InvokeOnFormThread(() =>
firstInput.Text = Defaults.FirstInput;
secondInput.Text = Defaults.SecondInput;
thirdChoice.SelectedIndex = Defaults.ThirdChoice;
);
// change Action to MethodInvoker for .Net versions less than 3.5
private void InvokeOnFormThread(Action behavior)
if (IsHandleCreated && InvokeRequired)
Invoke(behavior);
else
behavior();
作为一种做法,将表单中的所有公共方法都称为“InvokeOnFormThread”。或者,您可以使用 AOP 拦截表单上的公共方法调用并调用“InvokeOnFormThread”,但上述方法运行良好(如果您始终如一并记得始终在表单或 UserControls 上的公共方法上执行此操作)。
【讨论】:
【参考方案2】:看看使用现有的System.Action<T>
和System.Func<T,T>
代表:
control.Invoke(
new Action<int, string>(
(i, s) => MessageBox.Show(String.Format(s, i))), 1, "0");
int iret = (int) control.Invoke(new Func<int, int>(i1 => i1 + 1));
【讨论】:
很遗憾,但这些代表在 .net 2 中不可用。但是您可以轻松地声明它们。【参考方案3】:Michael Meadows 的回答是一个很好的例子,说明如何集中更新 GUI 表单的逻辑。
关于调用众多委托来同步前端的性能(我们很容易沉迷于此),不久前,我编写的软件在 GUI 同步方面优于等效的 C++(本机)Windows 应用程序!这一切都归功于BeginInvoke
和ThreadPool
类。
使用Action<>
和Func<>
代表和ThreadPool
类也是有益的,并考虑一般的Invoke
模式(上面由Michael 公开):
public void TheGuiInvokeMethod(Control source, string text)
if (InvokeRequired)
Invoke(new Action<Control, string>(TheGuiInvokeMethod, source, text);
else
// it is safe to update the GUI using the control
control.Text = text;
TheGuiInvokeMethod
真正位于表单或其他控件中的位置。
【讨论】:
【参考方案4】:我记得关闭检查并手动验证我使用的每个呼叫都是安全的。
由于我对某些线程的位置(信号量)有保证,或者因为它们调用了可以在其他进程上使用的底层 API 函数,它们中的许多可以称为跨线程。
我仍然得到了很多调用,通常是在上下文对象上,所以我可以使用 MethodInvoker。
我还在 Control.Invoke 中遇到了一个令人讨厌的错误,促使我编写自定义调用程序库。
【讨论】:
什么是错误...我从未遇到过讨厌的错误,但正如他们所说,知道是成功的一半,也许我出于无知而避免了。 :) 关闭一个调用挂起的控件会导致崩溃。只要拥有线程仍在消息循环中,我的自定义版本就会正确调用。以上是关于WinForms线程间修改的主要内容,如果未能解决你的问题,请参考以下文章