0

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.

thatguy
  • 21,059
  • 6
  • 30
  • 40
ScottexBoy
  • 452
  • 1
  • 4
  • 17
  • Create an interface, say IDispatcher, and add a class that implements it and exposes a few Dispatcher methods. Thanks to that solution you'll be able to write unit tests for code that uses dispatcher. – Maciek Świszczowski Dec 13 '20 at 23:37
  • I'm sorry isnt Dispatcher already a class from the base libraries of .net? – ScottexBoy Dec 14 '20 at 07:53

1 Answers1

2

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:

thatguy
  • 21,059
  • 6
  • 30
  • 40