- Collections that 开发者_开发技巧are bound in a WPF View must be updated on the UI thread.
- ViewModel exposes a collection
- Therefore when collection in the ViewModel is modified it must be done in the UI thread
- Best practice is to keep ViewModels ignorant of View and presumably such details as Dispatcher.
What is the cleanest way to resolve this while keeping view model testable?
One option here is to expose a SynchronizationContext usable from within the ViewModel. This is the mechanism the BackgroundWorker class uses to synchronize with the UI without introducing a dependency on WPF or Windows Forms, and allowing it to work with multiple technologies.
This would allow you to marshal back to the UI thread without taking a reference to the UI itself, including the Dispatcher.
You are right in that WPF gives us a Dispatcher
to make multi-threading simple; but if you want to separate concerns with the MVVM pattern, you'll need to implement a different threading strategy.
I've always found the BackgroundWorker
class more than enough to satisfy this, pushing updates back to the UI thread, such that you can update the ObservableCollection
in the VM and have changes propagate to the view.
This is quite well solved by abstracting all your logic of adding/deleting/updating observablecollections + any other complex logic that in your scenario occurs on different threads.
This controller class can be responsible for updating the ViewModel (It can have a reference to the VM by interface) on the correct thread.
One option is to create a subclass of ObservableCollection that overrides OnPropertyChanged and OnCollectionChanged and dispatches the appropriate events back to the UI thread (through something like SynchronizationContext).
This allows the ViewModel to be more agnostic when it comes to threading, it makes the code under test a lot easier to manage as well.
精彩评论