0

The below code is very simplified. I'm trying to abstract a dispatcher context so my view models can synchronize events that can only be raised on the GUI thread.

There's a circular reference in this pattern. Is there any other way to create a DispatcherObject? Am I doing it wrong?

I've read other questions like this, but the answers all seem to involve a reference to the DispatcherObject in the ViewModel. Is this an acceptable place for a circular reference?

class ViewModel {
    public DispatcherObject Dispatcher { get; set; }
}

class ModelView : UserControl {

    ModelView() {
        InitializeComponent();
        DataContext = new ViewModel { Dispatcher = this };
    }
}
qxn
  • 17,162
  • 3
  • 49
  • 72

3 Answers3

3

Generally speaking, circular references are something you want to avoid. Here are two alternatives:

1. Grab the dispatcher statically

The quick and dirty approach. Very easy to do, will work fine almost all of the time, but as with anything else done statically it does not lend itself to testability (which may or may not be a problem). In the rare instance where your WPF app has more than one UI thread you won't be able to use this approach blindly.

WPF: var dispatcher = Application.Current.Dispatcher;

Silverlight: var dispatcher = Deployment.Current.Dispatcher;

2. Make the dispatcher a dependency of the ViewModel

Configure your dependency injection container appropriately and have the Dispatcher be a dependency for those ViewModels that need to access it. This approach is more hassle but it allows you to work with multiple UI threads, is testable, and in general has all the usual pros/cons of doing things with DI.

Jon
  • 428,835
  • 81
  • 738
  • 806
  • Thanks. I went with an approach that is a sort of combination of the two. ViewModel's grab a Dispatcher defined statically, and that static instance can be updated by the application, unit test, whatever. – qxn May 04 '12 at 12:31
  • I also asked another question about the differences between Application.Current.Dispatcher and Dispatcher.CurrentDispatcher: http://stackoverflow.com/questions/10448987/dispatcher-currentdispatcher-vs-application-current-dispatcher – qxn May 04 '12 at 12:42
1

There is no need to get the specific dispatcher from the control. You can dispatch directly through the Deployment, i.e. Deployment.Current.Dispatcher.BeginInvoke(()=>something).

I usually don't provide the dispatcher object, but an action delegate. Then you can test without hopping threads by having the action just execute, while in production it can invoke on the Dispatcher.

Jeremy Likness
  • 7,531
  • 1
  • 23
  • 25
  • Thanks for the response, but it looks like the Deployment class is Silverlight-only. – qxn May 03 '12 at 22:55
  • This led me to a similar concept available in WPF: Dispatcher.CurrentDispatcher. http://msdn.microsoft.com/en-us/library/system.windows.threading.dispatcher.currentdispatcher%28v=vs.90%29.aspx – qxn May 04 '12 at 12:27
1

Why keep a reference to the DispatcherObject when what you actually need for invoking is the dispatcher itself?

class ViewModel {
    public Dispatcher Dispatcher { get; set; } }

class ModelView : UserControl {

    ModelView() {
        InitializeComponent();
        DataContext = new ViewModel { Dispatcher = Dispatcher };
    } }
Anton Tykhyy
  • 19,370
  • 5
  • 54
  • 56