开发者

WPF Dispatcher, Background worker and a whole lot of pain

Ok this may be really simple but everything I try just seems to hit a brick wall.

I have a view model with two properties, which are bound to my WPF form:

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

I have a method that I call to fetch some new pending items from outlook, however I also what to show some sort of progress on the form(spinning progress bar), the progress bar visibility is bound to the IsWorking property on the ViewModel, and a grid is bound to PendingItems collection.

I would like to be able to set the IsWorking to true so the UI can show the progress bar, run the work in the background and then set the IsWorking to false after it's finished so the progress bar goes away.

I开发者_运维问答 created a backgroudworker something like this:

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

Now worker_DoWork calls the method that goes of a fetches the pending items and adds them to PendingItems collection, everything runs in the background the UI is still responsive but I get the normal cross threaded error when trying to add to the collection. I wrapped the code that changes the collection in a dispatcher call:

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

but it still throws the same cross thread error.

I'm not very good with threading so I have no idea what I might be doing wrong, would someone be able to give me a hand with this?


have a look here for info on how other people have created thread safe observable collections (so you dont have to).


Since the code to update the collection is being called from a background thread, Dispatcher.CurrentDispatcher is the wrong dispatcher. You need to keep a reference to the UI's dispatcher and use that dispatcher when scheduling the update.


According to http://msdn.microsoft.com/en-us/library/system.windows.threading.dispatcher.currentdispatcher Because you call Dispatcher.CurrentDispatcher in the new thread (created by worker) it creates new dispatcher object. So you should get dispatcher from the calling thread (ui thread) in some way. Another option is to pass ui dispatcher to worker.RunWorkerAsync(object argument) as argument

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);
                            })
                          );

}
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜