2009-07-31 3 views
1

У меня есть окно с одной кнопкой внутри.Объясните странное поведение диспетчера (скрытая функция WPF)

Код фоновым является

private void Button_Click(object sender, RoutedEventArgs e) 
{ 
    Trace.TraceInformation("Button ThreadId: {0}", Thread.CurrentThread.ManagedThreadId); 

    Thread w = new Thread((ThreadStart) Worker); 
    w.SetApartmentState(ApartmentState.STA); // removing/adding this doesn't make effect 
    w.Start(); 
    MessageBox.Show("Direct"); 
} 

void Worker() 
{ 
    Trace.TraceInformation("Worker ThreadId: {0}", Thread.CurrentThread.ManagedThreadId); 

    this.Dispatcher.Invoke((Action)delegate 
           { 
            Trace.TraceInformation("Invoked ThreadId: {0}", Thread.CurrentThread.ManagedThreadId); 
            MessageBox.Show("Invoked"); 
           }); 
} 

Нажатие кнопки приводит в окна сообщений.

В то же время, трассировка показывает одни и те же номера для Кнопка ThreadId и Вызывается ThreadId.

+0

Тогда рабочий бежит по основной теме? Проверьте этот.Dispatcher.CheckAccess(), чтобы убедиться, что вызов был необходим. –

+0

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

+0

MessageBox.Show() - блокирующий вызов. То есть Button_Click не выходит, прежде чем я нажимаю на поле «Прямой». Я экспериментировал, разместив Trace.TraceInformation() до и после каждого окна сообщения. –

ответ

2

Диспетчер всегда выполняет работу с потоком графического интерфейса пользователя. Вот почему ваш ThreadId соответствует. Вы спрашиваете поток графического интерфейса - «что такое ваш ThreadId?» а затем выполнить некоторую работу через диспетчер, который снова переходит в поток графического интерфейса.

0

Я новичок в этом деле WPF Dispatcher, так что смешайте меня, если я полностью ошибаюсь, но похоже, что ваш звонок .Dispatcher - это действительно ваш диспетчер окна (UI thread). Таким образом, любой код будет выполняться потоком пользовательского интерфейса, а не потоком, созданным приложением.

[Редактировать]

Вот выход консоли я получил от выполнения кода

DispatcherQuestion.vshost.exe Information: 0 : Button ThreadId: 9 // UI Thread 
DispatcherQuestion.vshost.exe Information: 0 : Worker ThreadId: 11 // Thread w 
DispatcherQuestion.vshost.exe Information: 0 : Invoked ThreadId: 9 // UI Thread 

ThreadId 9 представляет собой пользовательский интерфейс резьбы. Ваша кнопка и ваш вызов Invoke выполняются, как и предусмотрено, потоком пользовательского интерфейса.

Я нашел this article today на MSDN, который действительно прояснил ситуацию с моделью WPF Threading/Dispatcher.

+0

В этом случае, почему ManagedThreadId соответствует? –

+0

Предполагается, что первый и последний вызовы ManagedThreadId совпадают. –

+1

Не имеет значения, что он сказал это. Он мог бы использовать диспетчер кнопок или любой другой диспетчер управления. Диспетчер выполняется в потоке пользовательского интерфейса всегда. – Charlie

1

После прогулки я понял, что происходит.

Это мое сообщение Идея, что не так с кодом (или причина, по которой вопрос был опубликован).

Button_Click выполнен в потоке Dispatcher. Нитка Dispatcher, как я знаю, является единственной для окна и его детей.

Даже если Button_Click занимает больше секунды (достаточно долго), и пользователю удастся снова нажать кнопку (или как-то иначе взаимодействовать с пользовательским интерфейсом), следующий Button_Click (или другой соответствующий обработчик) не будет выполнен немедленно, но будет помещен в диспетчеризации очереди.

Dispatcher.Invoke выполняет делегат в потоке пользовательского интерфейса. Invoke, я полагаю, отправляет сообщение делегату GetMessage() и блокирует вызывающий поток до тех пор, пока сообщение не завершится.

Я ожидал, что делегат приступит к исполнению только послеButton_Click выходов.

MessageBox.Show() является блокирующим вызовом. Следующий оператор не будет выполнен до того, как пользователь нажмет кнопку «ОК».

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

Но продолжает Отправка сообщений. В конце концов, это почему все пользовательские клики переводятся в Button.Click сообщения, и окно сообщения закрывается.

Именно поэтому вызываемый делегат выполнен доButton_Click выходов. Вызванный делегат разбивается наButton_Click.

P.S. Как вы видите в коде, делегат также вызывает MessageBox.Show(). Это приводит к появлению нового окна сообщений , который является модальным к предыдущему. Я заметил, что не могу нажать «ОК» на «Прямой» msgBox до «Вызывается».

+1

Вид. Вы близки. Прочтите эту статью очень внимательно. Это объясняет большинство всего, что вы пытаетесь поэкспериментировать, чтобы понять. http://msdn.microsoft.com/en-us/library/ms741870.aspx –

+0

Бинго! Эта функция называется «вложенными циклами». Спасибо! –

+0

Нет проблем. Удачи. –

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