Getting WPF Dispatcher from ViewModel

1,588 views
Skip to first unread message

Erick Thompson

unread,
Mar 17, 2009, 5:15:50 AM3/17/09
to altnet...@googlegroups.com
I'm writing a WPF MVVM application, and I want to use some multithreading to speed things up (I need to find some use for all these cores!), in particular data loading from remote sources (databases and web services). The problem is, I can't think of a good clean way to get the View's Dispatcher from the ViewModel. Without the dispatcher, I can't get back to the UI thread to update UI controls with my async content. Any thoughts?
 
Thanks,
Erick

Glenn Block

unread,
Mar 17, 2009, 5:20:46 AM3/17/09
to altnet...@googlegroups.com
Using the dispatcher in the ViewModel is not in itself a problem as it is a UI based model. You can certainky encapsulate it in a dispatch service if you like.
 
On that note, one thing you can look at is the EventAggregator we shipped with Prism. The EventAgg is a loosely coupled pub-sub mechansim, that fires messgaes which are marshalled either thorugh the UI thread or the background thread (it uses the dispatcher).
 
You can easily grab the Composite App Library within Prism and use only the event agg functionality.
 
I'd be happy to chat with you more on it's usage...

Regards
Glenn

Erick Thompson

unread,
Mar 17, 2009, 6:00:35 AM3/17/09
to altnet...@googlegroups.com
I'm glad I'm not the only one burning the midnight oil. :)
 
I can see the benefits of an event based model, as that way the UI can handle the event, and make sure (in UI code) that the reaction to the event (e.g., adding the item to the bound collection) is done on the right thread. However, I think it's overkill for what I need, as I've used this pattern (ThreadStart/dispatcher for slow binding code) in the past with good success. I should have phrased it a little differently - how do I get access to the Dispatcher/thread for a particular control from the ViewModel?
 
The issue is, I don't have a reference from the ViewModel to the View (at least, not directly). Basically, the View get its DataContext set to the ViewModel class instance, and unless I capture the thread when binding occurs, I don't see how to get the thread. What I really want is a thread-safe collection, where I can add items from any random thread, and the UI will handle the marshalling for me.
 
It's a little late, so please excuse me if I'm not making sense. :)
Thanks,
Erick

Glenn Block

unread,
Mar 17, 2009, 6:04:48 AM3/17/09
to altnet...@googlegroups.com
No worries...yes I am night owl as well.
 
EventAggregator is actually not a .NET Event based model :-) It does not require a direct connection to  the view. Instead it uses a delegate based publish / subscribe method which allows publishers and subscribers to indrectly connect via the event aggregator.
 
To get access to the Dispatcher you can access Dispatcher.Current.
 
The beauty of event aggregator is that the View and VM are NOT directly connected. Think of the event agg as an event bus of sorts that both use.
 
Glenn

Erick Thompson

unread,
Mar 17, 2009, 6:16:29 AM3/17/09
to altnet...@googlegroups.com
I'll take a look a the EventAggregator - it sounds like a nice solution for these types of situtations. I had thought of it as a UI command/message routing type of system, not used for data, but I can see now that it makes a lot of sense for data.
 
In the meantime, the issue I'm having is with the following code (cleaned up for clarity)
 
ThreadStart start = delegate()
{
   // repository is declared as a class field
   // This is the code that takes a while to run (~30 seconds)
   _entityRepository = new EntityRepository();
   Dispatcher.CurrentDispatcher.Invoke(new Action(delegate()
    {
        _allEntites.Clear();
        foreach (var v in _entityRepository.GetEntities())
        {
            _allEntites.Add(v);
        }
    }));
};
var threader = new Thread(start);
threader.Start();
The problem is, I get the exception "This type of CollectionView does not support changes to its SourceCollection from a thread different from the Dispatcher thread.". It would appear that the CurrentDispatcher is not getting the same Thread, which makes sense, as I'm calling CurrentDispatcher from within the newly spun up thread.
 
Thanks,
Erick

Erick Thompson

unread,
Mar 17, 2009, 6:21:40 AM3/17/09
to altnet...@googlegroups.com
Just after I sent this email, I realized what I missed. I just need to capture the CurrentDispatcher outside of the ThreadStart delegate. Duh. I think that means it's time for bed... :)
 
With that change, it works great, and the load happens on the second thread, but the UI updates occur via the UI thread. Tomorrow I figure out how to avoid the list creation, and use IEnumerables only.
 
Thanks,
Erick

Reply all
Reply to author
Forward
0 new messages