Диспетчер WPF, фоновый работник и много боли - PullRequest
6 голосов
/ 11 февраля 2010

Ладно, это может быть очень просто, но все, что я пытаюсь сделать, кажется, попадает в кирпичную стену.

У меня есть модель вида с двумя свойствами, которые привязаны к моей форме WPF:

 bool IsWorking {get;set;}
 ObservableCollection<OtherViewModel> PendingItems {get;set;}

У меня есть метод, который я вызываю, чтобы получить новые ожидающие элементы из outlook, однако мне также нужно показать какой-то прогресс в форме (вращающийся индикатор выполнения), видимость индикатора выполнения привязана к свойству IsWorking наViewModel, и сетка привязана к коллекции PendingItems.

Я хотел бы иметь возможность установить IsWorking в значение true, чтобы пользовательский интерфейс мог отображать индикатор выполнения, запускать работу в фоновом режиме и затем устанавливать IsWorking наfalse после завершения, поэтому индикатор выполнения исчезает.

Я создал фонового работника примерно так:

        worker = new BackgroundWorker();
        worker.DoWork += new DoWorkEventHandler(worker_DoWork);
        worker.RunWorkerCompleted += new RunWorkerCompletedEventHandler(worker_RunWorkerCompleted);
        worker.RunWorkerAsync();

Теперь worker_DoWork вызывает метод, который выполняет выборку ожидающих элементов и добавляет их в коллекцию PendingItems, все работает в фоновом режиме интерфейса пользователя.все еще отзывчив, но я получаю обычную перекрестную ошибку при попытке добавить в коллекцию.Я обернул код, который изменяет коллекцию, в вызов диспетчера:

        // Update to show the status dialog.
        Dispatcher.CurrentDispatcher.Invoke(DispatcherPriority.Render,
                            new Action(delegate()
                            {
                                this.PendingItems.Add(\\Blah);
                            })
                          );

, но все равно выдает ту же ошибку перекрестного потока.

Я не очень хорош с многопоточностью, поэтому у меня нетПонимаете, что я могу делать неправильно, кто-нибудь сможет мне помочь с этим?

Ответы [ 3 ]

5 голосов
/ 11 февраля 2010

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

4 голосов
/ 11 февраля 2010

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

0 голосов
/ 26 июля 2012

Согласно http://msdn.microsoft.com/en-us/library/system.windows.threading.dispatcher.currentdispatcher Поскольку вы вызываете Dispatcher.CurrentDispatcher в новом потоке (созданном работником), он создает новый объект диспетчера. Поэтому вы должны каким-то образом получить диспетчер из вызывающего потока (потока пользовательского интерфейса). Другой вариант - передать диспетчер пользовательского интерфейса в worker.RunWorkerAsync (аргумент объекта) в качестве аргумента

worker = new BackgroundWorker();
worker.DoWork += new DoWorkEventHandler(worker_DoWork);
worker.RunWorkerCompleted += new RunWorkerCompletedEventHandler(worker_RunWorkerCompleted);
worker.RunWorkerAsync(Dispatcher.CurrentDispatcher);

...

private void worker_DoWork(object sender, DoWorkEventArgs e)
{
   Dispatcher dispatcher = e.Argument as Dispatcher; // this is right ui dispatcher

   // Update to show the status dialog.
   dispatcher.Invoke(DispatcherPriority.Render,
                            new Action(delegate()
                            {
                                this.PendingItems.Add(\\Blah);
                            })
                          );

}
...