ScottexBoy
ScottexBoy

Reputation: 610

Autofac, how to resolve/inject Dispatcher?

I need to pass the dispatcher to update the UI:

container.RegisterType<Dispatcher>().AsSelf();
container.Register(c => new MyViewModel(c.Resolve<Dispatcher>(), ...some other arguments)).As<IMyViewModel>();

But since it's static, when I do container.Build(); I get this exception:

Autofac.Core.Activators.Reflection.NoConstructorsFoundException: 
'No accessible constructors were found for the type 'System.Windows.Threading.Dispatcher'.'

In my viewmodels I usually use it like _dispatcher?.Invoke('some code');.

I thought about removing it from the viewmodels contructors and in them just do _dispatcher = Dispatcher.CurrentDispatcher;, but since I'm working with threads im not sure if it is the best way to use it.

Upvotes: 0

Views: 377

Answers (1)

thatguy
thatguy

Reputation: 22119

By registering a dispatcher by RegisterType, Autofac will create a new instance of a dispatcher each time you try to resolve it. Since a Dispatcher only has an private parameterless constructor, you get the error that there is no accessible constructor. In general, you do not create dispatchers yourself.

When a Dispatcher is created on a thread, it becomes the only Dispatcher that can be associated with the thread, even if the Dispatcher is shut down.

If you attempt to get the CurrentDispatcher for the current thread and a Dispatcher is not associated with the thread, a Dispatcher will be created. A Dispatcher is also created when you create a DispatcherObject. If you create a Dispatcher on a background thread, be sure to shut down the dispatcher before exiting the thread.

The dispatcher of the user interface thread can be accessed using Application.Current.Dispatcher. Since this dispatcher already exists and is a unique instance, you have to register this instance as singleton.

container.RegisterInstance(Application.Current.Dispatcher).AsSelf();

Then you can resolve it anywhere by the type Dispatcher, because you registered it AsSelf.

var dispatcher = container.Resolve<Dispatcher>();

Regarding unit testing your view models, passing a Dispatcher is unfortunate. It does not implement a suitable interface to mock it and is sealed, so you can derive it. However, there are solutions:

Upvotes: 2

Related Questions