2013-04-05 3 views
2

Я использую потоки для запуска длинных операций в пользовательском интерфейсе моей программы, чтобы он не блокировался. Однако в этих задачах мне нужно обновить элементы управления, что невозможно не из потока, на котором они были созданы. Рекомендуется использовать control.BeginInvoke (Delegate) для выполнения метода, который вы хотите.C# Control.Invoke группа методов

Однако для этого вам необходимо объявить тип делегата, и только тогда вы можете их вызвать.

Таким образом, это выглядит следующим образом: если я хочу, чтобы выполнить методу пустот Update(), я должен идти:

delegate void CallbackVoid(); 
void Update() {...} 

...(in task code)... 
this.BeginInvoke(new CallbackVoid(Update)); 

Это довольно утомительно делать для каждого метода там. Не могу я просто как-то сделать это, естественно, как:

void Update() {...}  
this.BeginInvoke(Update); 

ответ

1

Обновлено: ПРОИЗВЕДЕНИЙ ДЛЯ WPF !!!

Вы можете использовать короткий синтаксис с анонимными методами, даже не объявляя ваши методы

Dispatcher.BeginInvoke(DispatcherPriority.Background, new MethodInvoker(() => 
       { 
        //Your Update code 
       })); 
+0

Как это отличается от control.Invoke (новый EventHandler (делегат {/ * update control here * /})); ? Что лучше? – Arie

+0

@Arie Оба правильные, но не другие. MSDN говорит: «Делегат может быть экземпляром EventHandler, и в этом случае параметр отправителя будет содержать этот элемент управления, а параметр события будет содержать EventArgs.Empty. Делегат может также быть экземпляром MethodInvoker или любым другим делегатом, который принимает список параметров void. Вызов делегата EventHandler или MethodInvoker будет быстрее, чем вызов другого типа делегата « – Alex

+0

@voo: На самом деле это * неверно для Windows Forms, и это вопрос, о котором идет речь ... –

2

Один вариант, который упрощенным вещи, чтобы добавить метод расширения:

public static void BeginInvokeAction(this Control control, Action action) 
{ 
    control.BeginInvoke(action); 
} 

Тогда вы можете просто использовать :

this.BeginInvokeAction(action); 

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

0

Попробуйте следующее:

if (this.controlname.InvokeRequired && !this.controlname.IsDisposed) 
       { 
        Invoke(new MethodInvoker(delegate() 
         { 
          //Update control on GUI here! 

    })); 
    else if(!this.controlname.IsDisposed) 
    { 
          //AND here! 
    } 
+0

Это существенно больше * кода, не менее, и не имеет никаких преимуществ перед любым другим решением. Вся идея в том, что OP * знает * он а не в потоке пользовательского интерфейса, нет необходимости проверять, и он знает, что элементы управления не расположены (если бы не было честно лучше просто сбой, чтобы вы могли найти/исправить ошибку, а не продолжать). – Servy

0

BeginInvoke асинхронный, Invoke является синхронным, который один вы используете, зависит от того, что вы пытаетесь сделать. Если вам необходимо завершить вызов до того, как вы перейдете, вам нужны синхронные вызовы.

Вот моя любимая конструкция для синхронных Запускает:

static void InvokeIfRequired(Control control, Action action) 
{ 
    if (control.InvokeRequired) 
    { 
     control.Invoke(action); 
    } 
    else 
    { 
     action.Invoke(); 
    } 
} 

Использована

void MyTestFunction() 
{ 
    InvokeIfRequired(myControl,() => 
     { 
      MyFunction(); 
      MyOtherFunction(); 
     }); 

    // Or more simply: 
    InvokeIfRequired(myControl,() => MyFunction()); 
} 

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

Смежные вопросы