2013-03-19 2 views
23

Я использовал эту функцию в Windows forms применения:InvokeRequired в МОФ

delegate void ParametrizedMethodInvoker5(int arg); 

private void log_left_accs(int arg) 
{ 
    if (InvokeRequired) 
    { 
     Invoke(new ParametrizedMethodInvoker5(log_left_accs), arg); 
     return; 
    } 

    label2.Text = arg.ToString(); 
} 

Но в WPF он не работает. Зачем?

ответ

0

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

Вы должны использовать Dispatcher.Invoke для добавления делегата в поток пользовательского интерфейса в приложении WPF.

Также стоит отметить, что InvokeRequired действительно не требуется в приложении winform, и это не то, что вы должны проверять в приложении WPF. Вы должны знать, что вы не находитесь в потоке пользовательского интерфейса, когда звоните Invoke. Вы никогда не должны находиться в ситуации, когда данный метод иногда вызывается из потока пользовательского интерфейса и иногда вызывается из фонового потока. Выбери один; либо всегда заставляют вызывающего абонента ссылаться на поток пользовательского интерфейса перед вызовом заданного метода (поэтому вам не нужно вызывать) или предположить, что вызывающий объект не будет в потоке пользовательского интерфейса при вызове метода. Также стоит отметить, что вызов Invoke, когда вы уже находитесь в потоке пользовательского интерфейса, просто замечательный. Ошибок или проблем, которые могут возникнуть из-за случайного экземпляра повторного вызова потока пользовательского интерфейса, не существует. Это незначительная стоимость исполнения, поэтому просто не добавляйте ненужный код для всего этого места.

+4

Конечно, есть много ситуаций, когда вы не знаете, находитесь ли вы в создании потока или нет, и вам нужно его проверить! – Christoph

+1

Когда-либо создавался пользовательский контроль, который позволяет привязываться к данным? Обычно данные извлекаются другим потоком, но, например, установка значения текстового поля также может быть выполнена другим элементом управления (например, изменение выпадающего списка в другом значении по умолчанию =>, которое вы используете в потоке пользовательского интерфейса. Назначение значения из базы данных => вы находитесь в рабочем потоке) – Christoph

+0

путь, НЕ используйте Invoke(), вместо этого используйте BeginInvoke() (как в WinForms, так и в WPF). Причина в том, что Invoke() может уступать уродливым мертвым замкам. – Christoph

9

В WPF использовать CheckAccess метод вместо InvokeRequired

if (!CheckAccess()) { 
    // On a different thread 
    Dispatcher.Invoke(() => log_left_accs(arg)); 
    return; 
} 
+0

А как насчет Invoke? – oehgr

+0

CheckAccess - это метод диспетчера, а не метод Window или control –

+0

@oehgr использовать 'Dispatcher.Invoke'.Я обновлю myanswer – JaredPar

38

В WPF, метод Invoke находится на диспетчеру, так что вам нужно позвонить Dispatcher.Invoke вместо Invoke. Кроме того, нет свойства InvokeRequired, но у диспетчера есть метод CheckAccess (по какой-то причине он скрыт в intellisense). Таким образом, ваш код должен быть:

delegate void ParametrizedMethodInvoker5(int arg); 
void log_left_accs(int arg) 
{ 
    if (!Dispatcher.CheckAccess()) // CheckAccess returns true if you're on the dispatcher thread 
    { 
     Dispatcher.Invoke(new ParametrizedMethodInvoker5(log_left_accs), arg); 
     return; 
    } 
    label2.Text= arg.ToString(); 
} 
+1

Значение 'Dispatcher' может быть' null'. Вот почему 'DispatcherObject' имеет метод' CheckAccess', он учитывает эту возможность – JaredPar

+0

@ JaredPar, знаете ли вы, в этом случае Диспетчер может быть пустым? Я никогда не видел его раньше ... –

+0

Я верю, что когда объект заморожен, его 'Dispatcher' будет' null'. Ищите ссылки на 'DispatherObject.DetachFromDispatcher' – JaredPar

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