Потоковая проблема с Dispatcher.Invoke и Dispatcher.BeginInvoke - PullRequest
2 голосов
/ 14 декабря 2010

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

 EDisc.App.Current.Dispatcher.
              Invoke(
                              DispatcherPriority.Normal, new Action(delegate
                              {
                                  context = NavigationManager.CurrentPage.DataContext;
                              }));

Значение контекста возвращается. Однако с кодом ниже

 EDisc.App.Current.Dispatcher.
              BeginInvoke(
                              DispatcherPriority.Normal, new Action(delegate
                              {
                                  context = NavigationManager.CurrentPage.DataContext;
                              }));

Контекст нулевой, и я получаю исключение InvalidOperation, говорящее "

Вызывающий поток не может получить доступ к этому объекту, потому что другой поток владеет им. Я вызываю это из службы WCF, которая выполняется с UseSynchronizationContext = false. Кто-нибудь может объяснить это поведение?

1 Ответ

2 голосов
/ 14 декабря 2010

И BeginInvoke, и Invoke в итоге вызовут внутренний метод с именем BeginInvokeImpl для выполнения работы.Разница в том, что Invoke затем ждет завершения операции перед возвратом.

И есть еще одно отличие: если вы уже находитесь в потоке пользовательского интерфейса и , вы используете DispatcherPriority.Send Invoke будет фактически вызывать метод напрямую, не проходя через BeginInvokeImpl, что означает, что операция обрабатывается без прохождения через очередь сообщений.(Если вы не используете Send, то любые другие сообщения, уже поставленные в очередь с более высоким свойством, чем ваша операция, будут обработаны первыми.)

Но так как вы, вероятно, не находитесь в потоке пользовательского интерфейса здесь - вы 'на некоторый обратный вызов WCF - этот особый случай не будет применяться.Таким образом, Invoke в итоге вызывает ту же базовую реализацию, что и BeginInvoke.

Из предоставленной вами информации, я должен был бы догадаться, что где-то здесь отсутствует деталь.Код, который вы показали, должен работать нормально, если, возможно, у вас нет нескольких потоков пользовательского интерфейса в вашем приложении, и страница, которая оказывается в CurrentPage, время от времени принадлежит различным потокам.

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

Кстати, один из способов, которым вы можете случайно получить несколько потоков пользовательского интерфейса, - это создание объекта пользовательского интерфейса (например, страницы).) в каком-то рабочем потоке или обратном вызове.Возможно ли, что вы это где-то сделали?

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...