multithreading - WinForms 线程安全控件

标签 multithreading winforms controls

我花了很多时间处理 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/

相关文章:

silverlight - 找到更好的控制

c# - 我的控件使用的工具箱中的 "hide"控件如何使用?

java - 在多线程环境中读取的值

c# - 发布版本中 visual studio 2010 中的核心转储

c# - 如何在表单中动态添加自定义控件

javascript - 如何在 Google map V3 中定位自定义 controlUI?

ios - iOS 应用程序的后台更新问题

c++ - 外部进程与线程和数据处理

multithreading - 为什么 'Google Chrome Renderer' 是多进程,而不是多线程?

c# - c#调用窗体后如何返回调用方法?