4

我经常在我的 GUI 代码中写这样的东西:

private void SecondTimer_Elapsed(object sender, ElapsedEventArgs e)
{
    if (progressBar1.InvokeRequired)
    {
      progressBar1.BeginInvoke(new ElapsedEventHandler(SecondTimer_Elapsed), new[] {sender, e});
      return;
    }
//Code goes here
}

当然,如果应用程序是多线程的,这是必要的,因为我们需要编组最初创建控件的线程。问题是,编写委托并将参数放入数组中可能很乏味,并且在每个此类事件处理程序的顶部占用空间。是否有属性或类似的东西可以为您替换此代码?基本上是一个标签,上面写着“如果您在错误的线程上,请在 GUI 线程上使用相同的参数再次给我打电话。”

4

3 回答 3

13

我不知道类似的事情,但这可能对您来说是一种有用的扩展方法:

public static class Extensions
{
    public static void Execute(this ISynchronizeInvoke invoker,
                               MethodInvoker action)
    {
        if (invoker.InvokeRequired)
        {
             invoker.BeginInvoke(action);
        }
        else
        {
             action();
        }
    }
}

现在这只适用于无参数委托,当然......但对于 lambda 表达式来说,这不是问题:

progressBar1.Execute(() => SecondTimer_Elapsed(sender, e));

这具有以下优点:

  • 写起来很简单
  • 签名不会出错(您不依赖后期绑定)
  • MethodInvoker我相信比其他代表更有效地执行
  • 如果你没有太多代码要执行,你可以将它内联写在 lambda 表达式中
于 2010-08-15T20:55:32.683 回答
3

您可以使用扩展方法来整理它:

// Extension methods.
public static void BeginInvoke(this ISynchronizeInvoke @this, MethodInvoker action) {
    if (@this.InvokeRequired) @this.BeginInvoke(action);
    else action();
}

public static void BeginInvoke<T1, T2>(this ISynchronizeInvoke @this, Action<T1, T2> action, T1 arg1, T2 arg2) {
    if (@this.InvokeRequired) @this.BeginInvoke(action, new object[] { arg1, arg2 });
    else action(arg1, arg2);
}

// Code elsewhere.
progressBar1.BeginInvoke(() => SecondTimer_Elapsed(sender, e));
// Or:
progressBar1.BeginInvoke(SecondTimer_Elapsed, sender, e);

编辑: Jon Skeet 说使用 MethodInvoker 委托更快是正确的。从MSDN

对一个EventHandlerMethodInvoker委托的调用将比对另一种类型的委托的调用更快。

于 2010-08-15T21:01:39.070 回答
0

为此获取一个AOP 框架。您可以创建一个MethodInterceptionAspect在调用函数时触发的函数。然后你可以进行检查,或者将函数(你有一个函数的引用和它的参数)扔给 GUI 线程,或者直接执行它。

优点是您必须编写此代码一次,并且只需一个属性即可将其应用于所需的每个属性。

于 2010-08-15T20:56:22.203 回答