Использование диспетчера C # - PullRequest
21 голосов
/ 20 октября 2011

Я создаю чат-клиент и не на 100% уверен в том, как использовать dispatcher. Итак, вопрос в том, что у меня есть метод как таковой:

public void LostConnection()
{
    myGUI.chatBox.AppendText("Lost connection to room: "+ myGUI.UsernameText.ToString() + "\r\n");
}

Нужно ли вводить утверждение в (myGUI.chatBox... ) с Dispatcher.Invoke? Я ценю любую помощь.

Ответы [ 2 ]

78 голосов
/ 20 октября 2011

Ваше приложение имеет основной поток пользовательского интерфейса (обычно ManagedThreadId==1).Как правило, в приложении чата ваши события поступают в другие потоки (либо выделенные потоки прослушивания сокетов, либо потоки пула потоков из кода прослушивания).Если вы хотите обновить пользовательский интерфейс из события, которое получает другой поток, вы должны использовать диспетчер.Полезным тестом здесь является метод Dispatcher.CheckAccess(), который возвращает true, если код находится в потоке пользовательского интерфейса, и false, если в каком-то другом потоке.Типичный вызов выглядит примерно так:

using System.Windows.Threading; // For Dispatcher.

if (Application.Current.Dispatcher.CheckAccess()) {
    network_links.Add(new NetworkLinkVM(link, start_node, end_node));
}
else {
    Application.Current.Dispatcher.BeginInvoke(DispatcherPriority.Normal, new Action(()=>{
        network_links.Add(new NetworkLinkVM(link, start_node, end_node));
    }));
}

Если вы находитесь в главном окне, вы можете использовать:

Dispatcher.BeginInvoke(...

Если вы находитесь в каком-либо ином контексте, например модели представления, используйте:

Application.Current.Dispatcher.BeginInvoke(  

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

MessageBox, Dispatchers и Invoke / BeginInvoke:
Dispatcher.Invoke будет блокировать ваш поток до тех пор, пока MessageBox не будет удален.
Dispatcher.BeginInvoke позволит продолжить выполнение кода вашего потока, в то время как поток пользовательского интерфейса будет блокировать вызов MessageBox до тех пор, пока он не будет отменен.

CurrentDispatcher против Current.Dispatcher!
Остерегайтесь Dispatcher.CurrentDispatcher, так как я понимаю, что это вернет Dispatcher для текущего потока, а не потока пользовательского интерфейса.Обычно вас интересует диспетчер в потоке пользовательского интерфейса - Application.Current.Dispatcher всегда возвращает это.

Дополнительные примечания:
Если вы обнаружите, что вам приходится часто проверять диспетчер CheckAccess, тополезный вспомогательный метод:

public void DispatchIfNecessary(Action action) {
    if (!Dispatcher.CheckAccess())
        Dispatcher.Invoke(action);
    else
        action.Invoke();
}

, который можно назвать:

DispatchIfNecessary(() => {
    network_links.Add(new NetworkLinkVM(link, start_node, end_node));
});
2 голосов
/ 20 октября 2011

Как-то так (с макушки головы) должно работать:

public void LostConnection() 
{ 
   myGUI.Invoke
      ((MethodInvoker)delegate
   {
      myGUI.chatBox.AppendText("Lost connection to room: "+ myGUI.UsernameText.ToString() + "\r\n"); 
   });
}
...