Monday, April 25, 2011

WPF: Dispatcher - Common Scenarios

In WPF circles, when someone mentions "the Dispatcher" they usually mean the instance of the Dispatcher class associated with the UI thread. When using the canonical WPF application startup pattern, this Dispatcher is initialized automagically and is often the only instance ever created during the life of the process.

Most of the classes in WPF enforce thread affinity. If you are developing a multi-threaded application, you must make sure that the visual elements of your application are only accessed on the UI thread. Generally, this means finding "the Dispatcher" and pushing whatever work you require onto its queue.

There are many ways to find "the Dispatcher"; your approach will depend on the complexity of your application and the purity of your architecture:
  • Brute force: Provided you aren't playing any games with multiple AppDomains, Application.Current.Dispatcher will give you the reference you need.
  • View access: All WPF visual elements derive from DispatcherObject. If you have access to a visual element, you can inspect its Dispatcher property.
  • Saving for later: During application startup, if you can guarantee that you are running on the UI thread, store a reference to Dispatcher.CurrentDispatcher for later use while your view models are being initialized.
There are two methods on Dispatcher that queue up new work: BeginInvoke() and Invoke(). BeginInvoke() operates asynchronously, has fewer overloads to wade through, and gives you control over operation cancellation and reprioritization. Invoke() operates synchronously, has twice as many overloads due to extra TimeSpan arguments, and effectively freezes any progress on the thread making the call. While there are cases where Invoke() may be more appropriate, BeginInvoke() supersets its functionality and is more often the superior choice.

[Deadmau5: A City in Florida -- YouTube]

References

No comments:

Post a Comment