2014-01-11 21 views
1

在阅读了如何使用Invoke从其他线程更新GUI元素之后,我对它做了一些工作,并以下面的方法来处理它。我相当肯定我对解决方案过于复杂,但我确实相信它是按预期工作的。使用Invoke处理来自其他线程的调用。这是一个很好的模式?

我用这种方法看到的优点是,它允许一旦GUI线程准备就绪,并且命令的顺序保持不变,多个命令可以短时间连续存储以供使用。缺点是,对我来说,存储这些临时参数看起来效率低下(我可以创建一个通用类来存储所有隐藏它们到单个对象)

我选择重复使用相同的互斥对所有调用,但不同的可能只要他们搭配起来就可以使用。

那么还有什么其他模式可以用来获得相同的结果? (希望在一个不太令人费解的做法)

//The main form class. 
public class GUIHandler 
{ 
    Mutex InvokeOnce = new Mutex(); //Mutex that ensures that temp storage only gets written to or read from 

    //tempData for Invoke Methodes 
    List<SomeObject> invokeParameter = new List<SomeObject>(); 
    List<SomeOtherObject> anotherInvokeParameter = new List<SomeOtherObject>(); 

    public GUIHandler() 
    { 
     //Some code to initialize the GUI 
    } 

    //Generic Reused InvokeDelegate 
    public delegate void InvokeDelegate(); 

    //External Call with parameters different calls different names 
    private void SomeInvokeRequiredAction(SomeObject someParameter) 
    { 
     //call mutex for handle the storage and store the parameter 
     InvokeOnce.WaitOne(); 
     invokeParameter.Add(someParameter); 
     InvokeOnce.ReleaseMutex(); 
     this.BeginInvoke(new InvokeDelegate(SomeInvokeRequiredActionInvoke)); 
    } 

    //Invoked Code with related name to its primary external call 
    private void SomeInvokeRequiredActionInvoke() 
    { 
     InvokeOnce.WaitOne(); 
     //some random action on a GUI element that required the Invoke in first place 
     guiElement.Text = invokeParameter[0] 
     invokeParameter.RemoveAt(0); 

     InvokeOnce.ReleaseMutex(); 
    } 
} 
+0

使用的invoke()代替BeginInvoke()不太复杂。不需要锁定,因为只有一个线程可以同时访问列表。然而,它当然不是更有效率。一次调用单个数据项通常是一个非常糟糕的主意,因此调用UI线程的几率很高。你只有人的眼睛才能娱乐,他们看不到每秒超过25次更新的内容。 –

+0

你可能想看看这个问题,它的答案是:[自动化InvokeRequired代码模式](http://stackoverflow.com/questions/2367718/automating-the-invokerequired-code-pattern) –

+0

典型的我使用lambdas捕获用于存储用于调用的变量。它是类型安全的,并且需要存储变量的类是在编译时为您创建的。 – Aron

回答

1

如果您需要的是:

  1. 通工作到UI线程。
  2. 保留该作品的订单。

你不需要比简单的调用更多。它是线程安全的(所以不需要锁定)。它搜索最顶层的控件,它是窗口句柄并排队工作以运行它(消息循环)。而且因为它只是一个单一的线程,工作将按顺序完成。

如该在意见提出的问题,像这样的一个简单的解决方案可能是不够的:

用法:

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(); 
    } 
} 
相关问题