使用WinForms GUI Control进行线程安全事件

时间:2012-08-11 18:58:08

标签: c# multithreading events delegates

我知道GUI组件不能在不同的线程中使用。所以你通常会做一个方法来检查InvokeRequired,然后调用Invoke等。但这是很多代码。有没有办法做这样的事情:MyEvent += myDelegate这个myDelegate将从分配它的线程执行? 为什么Invoke方法只能从Control类中获得?我唯一的想法是制作自己的方法,如AddDelegate(委托..,控制c)或类似的东西。

知道如何实现这个目标吗?

4 个答案:

答案 0 :(得分:4)

为了避免这种重复代码,我通常创建一个类来隔离这个逻辑。当应用程序启动时,我会初始化此类并在整个应用程序中使用它。优点是它可以在控件之外使用。

public static class UI
{
    private static Control internalControl;

    public static void Initialize(Control control)
    {
        internalControl = control;
    }

    public static void Invoke(Action action)
    {
        if (internalControl.InvokeRequired)
        {
            internalControl.Invoke(action);
        }
        else
        {
            action();
        }
    }
}

初始化主表单时初始化:

UI.Initialize(this);

用法:

UI.Invoke(() => { this.Text = "Test"; });

答案 1 :(得分:2)

我使用了一种相当简单的方法:

private void execThreadSafeMethod(Control ctrl)
{
     MethodInvoker method = (MethodInvoker) delegate
     {
         //Do something that you always wanted to do :)
     }
     if(ctrl.InvokeRequired == true)
     {
          ctrl.Invoke(method);
     }
     {
          method.Invoke();
     }
}

答案 2 :(得分:1)

您使用的是.Net 4吗?如果是这样,您可以使用异步任务。

您可以从创建控件的主线程的同步上下文创建一个TaskScheduler。

var uiTaskScheduler = TaskScheduler.FromCurrentSynchronizationContext();

然后你可以在后台线程上运行的任何方法中使用它来更新主线程上的任何控件。

Task.Factory.StartNew(
    () => { MessageBox.Show("Message from separate thread.") }, 
    CancellationToken.None, 
    TaskCreationOptions.None, 
    uiTaskScheduler);

答案 3 :(得分:1)

保持等待找到我的方法,但我没有看到它(希望我正确地阅读了这个问题)

这是我在单独的线程中处理Invokes的方式:

this.Invoke((MethodInvoker)delegate() { /*whatever I need done*/ });

这很好,因为您可以将代码保留在适用的位置,而不是跳转

this.Invoke((MethodInvoker)delegate() {
    //here is some code I need to run on the main thread
    //usually making a label visible or some other bs
    //might want to resize my form or update a list box, who knows
});