我花了很多时间处理 Windows 窗体控件,但从后台工作线程开始 - 我认为这是一种很好的做法,因为您不希望当人们单击按钮时您的窗体被锁定。老实说,我通常在后台工作线程中执行几乎所有与 GUI 相关的操作,因此界面对用户的响应很好(希望更多人会这样做!)。
所以我的问题是......每次我必须与控件交互时,我都必须“调用”它们,例如:
if (control.InvokeRequired)
{
//
}
标准做法对吗?但是,这会导致我编写一些非常困惑的代码,因为几乎我拥有的每种控件类型,我都需要一个 MethodInvoker 委托(delegate)或其他东西。它在我的保护中添加了数千行代码,而且非常耗时。
我目前有数百种“属性设置”方法,例如:
private void Safe_SetLableText(Label control, string text)
{
if (control.InvokeRequired)
{
control.Invoke((MethodInvoker)delegate
{
control.Text = text;
});
}
else
{
control.Text = text;
}
}
那么,是否有其他技术或方法可以做到这一点,或者某种方式能够始终改变控件的属性,无论控件是什么,无论我在哪个线程中?
类似于:(伪代码)
BackgroundWorker.RunWorkerAsync();
private void thing_to_do()
{
// We are in a background thread now
DoSomeDatabaseWorkThatTakesALongTime();
InvokeAnyControls();
// Do some stuff...
controlX.Text = "123"
controlY.Height = 300;
controlZ.text = ControlA.text;
RestoreAnyControls();
}
最佳答案
你可以包装你的InvokeRequired
带有委托(delegate)的代码,如下所示:
public static void Invoke2<TControl>(this TControl c, Action<TControl> code) where TControl : Control {
if( c.InvokeRequired ) c.Invoke( delegate() { code(c); } );
else code(c);
}
然后像这样使用它:
private void Safe_SetLableText(Label control, string text) {
control.Invoke2( c => c.Text = text );
}
当然你可能想要比
Invoke2
更好的名字。 ,但我希望这个想法与您同在。请注意,lambda 表达式语法是 C# 3.0 的一个特性,但 Action<T>
委托(delegate)是 .NET 2.0 的一部分,因此只要您是 VS2008 或更高版本,它将针对 .NET Framework 2.0 进行编译。
关于multithreading - WinForms 线程安全控件,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/18053298/