C# 使用Invoke处理来自其他线程的调用。这是一个好的模式吗?

C# 使用Invoke处理来自其他线程的调用。这是一个好的模式吗?,c#,multithreading,winforms,invoke,ui-thread,C#,Multithreading,Winforms,Invoke,Ui Thread,在阅读了如何使用Invoke从其他线程更新GUI元素之后,我对它进行了一些研究,并最终采用了以下方法来处理它。我相当肯定我已经把解决方案复杂化了,但我确实相信它正在按预期工作 我所看到的这种方法的优点是,一旦GUI线程准备就绪,它允许在短时间内连续存储多个命令以供使用,并且命令的顺序得到维护。缺点是,对我来说,存储这些临时参数似乎效率低下(我可以创建一个泛型类来存储所有参数,从而将它们隐藏到单个对象中) 我已经选择对所有调用重复使用相同的互斥,但只要它们配对,就可以使用不同的互斥 那么,我可以使

在阅读了如何使用Invoke从其他线程更新GUI元素之后,我对它进行了一些研究,并最终采用了以下方法来处理它。我相当肯定我已经把解决方案复杂化了,但我确实相信它正在按预期工作

我所看到的这种方法的优点是,一旦GUI线程准备就绪,它允许在短时间内连续存储多个命令以供使用,并且命令的顺序得到维护。缺点是,对我来说,存储这些临时参数似乎效率低下(我可以创建一个泛型类来存储所有参数,从而将它们隐藏到单个对象中)

我已经选择对所有调用重复使用相同的互斥,但只要它们配对,就可以使用不同的互斥

那么,我可以使用哪些其他模式来获得相同的结果呢?(希望采用不那么复杂的方法。)

//主窗体类。
公共类GUIHandler
{
Mutex InvokeOnce=new Mutex();//确保临时存储只写入或读取的互斥体
//调用方法的tempData
List invokeParameter=new List();
List anotherInvokeParameter=新列表();
公共GUIHandler()
{
//一些初始化GUI的代码
}   
//通用重用InvokeDelegate
公共委托void InvokeDelegate();
//参数不同的外部调用调用不同的名称
私有void SomeInvokeRequestAction(SomeObject someParameter)
{
//调用互斥来处理存储并存储参数
InvokeOnce.WaitOne();
invokeParameter.Add(someParameter);
InvokeOnce.ReleaseMutex();
this.BeginInvoke(newinvokedelegate(someinvokererequiredActionInvoke));
}
//调用的代码的名称与其主要外部调用相关
私有void someinvokererequiredactioninvoke()
{
InvokeOnce.WaitOne();
//GUI元素上的一些随机操作首先需要调用
guiElement.Text=invokeParameter[0]
invokeParameter.RemoveAt(0);
InvokeOnce.ReleaseMutex();
}
}

如果您需要:

  • 将工作传递给UI线程
  • 维护那项工作的秩序
  • 您只需要一个简单的调用。它是线程安全的(因此不需要锁定)。它搜索最顶端的控件及其窗口句柄,并将要在其上运行的工作排队(消息循环)。因为这只是一个线程,所以工作将按顺序完成

    正如在评论中提出的问题,像这样一个简单的解决方案可能就足够了:

    用法:

    button.InvokeIfRequired(() =>
    {
        // This will run under the UI thread.
        button.Text = "hamster";
    });
    
    实施:

    public static void InvokeIfRequired(this ISynchronizeInvoke control, MethodInvoker action)
    {
        if (control.InvokeRequired)
        {
            control.Invoke(action);
        }
        else
        {
            action();
        }
    }
    

    使用Invoke()而不是BeginInvoke()不太复杂。不需要锁定,因为只有一个线程可以同时访问列表。然而,这肯定不是更有效率。一次调用一个数据项通常是一个非常糟糕的主意,对UI线程进行火处理的可能性很高。你只有人类的眼睛来娱乐,他们看不到超过每秒25次更新的任何东西。你可能想看看这个问题及其答案:典型的我使用lambdas和capture来存储调用变量。它是类型安全的,存储变量所需的类是在编译时为您创建的。
    public static void InvokeIfRequired(this ISynchronizeInvoke control, MethodInvoker action)
    {
        if (control.InvokeRequired)
        {
            control.Invoke(action);
        }
        else
        {
            action();
        }
    }