Есть ли сокращение для Form.BeginInvoke? - PullRequest
4 голосов
/ 16 августа 2010

Довольно часто в моем коде 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 с теми же аргументами. «

Ответы [ 3 ]

13 голосов
/ 16 августа 2010

Я не знаю ничего подобного, но это, вероятно, будет полезным для вас методом расширения:

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

Теперь это работает только для делегатов без параметров, конечно ... но сЛямбда-выражения, которые не должны быть проблемой:

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

Это имеет следующие преимущества:

  • Писать просто
  • Вы не ошибетесьс подписью (вы не полагаетесь на позднюю привязку)
  • MethodInvoker выполняется немного более эффективно, чем другие делегаты, я считаю,
  • Если у вас нет большого кода для выполнения,Вы можете написать его в виде лямбда-выражения
3 голосов
/ 16 августа 2010

Вы можете исправить это с помощью методов расширения:

// 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);

Редактировать: Джон Скит прав, говоря, что использование делегата MethodInvoker быстрее.От MSDN :

Вызов делегату EventHandler или MethodInvoker будет быстрее, чем вызов делегата другого типа.

0 голосов
/ 16 августа 2010

Возьмите AOP framework для этого. Вы можете создать MethodInterceptionAspect, который срабатывает при вызове функции. Затем вы можете выполнить проверки и либо передать функцию (у вас есть ссылка на функцию и ее аргументы) в поток GUI, либо выполнить ее напрямую.

Преимущество заключается в том, что вам придется написать этот код один раз и применить его к каждому необходимому свойству, используя только атрибут.

...