1

My project is built with Catel.MVVM, but I am very open to any solution for WPF MVVM with DI that is not Catel.MVVM specific to solve my problem. The project is .NET 5.

I am struggling to get a solution for DI injecting dependencies into ViewModels with Catel.MVVM. I'm using the .NET Core implementation of DI.

What I want:

  1. Have DI inject dependencies into ViewModels when showing Views. Right now without a parameter-less constructor the ViewModel throws an exception due to the DI not creating the ViewModel.
  2. Have Catel.MVVM auto associate the ViewModel for each View so that it does not need to be set in XAML.

I know this is possible with Catel.MVVM because I see it working in the WildGums project LogViewer, but I am having trouble wrapping my head around how it works. I have also browsed through each WPF project in Catel.Examples. I'm either overlooking something or just do not understand how WPF MVVM with DI works. This is my first time using DI with MVVM.

I thought I would be lucky and this would be handled automatically if I use the naming conventions described in the docs.

I have a project with Catel.MVVM & working DI with the exception of ViewModel injection, CatelMvvmDI. As the project sits, ViewModel association is handled in XAML.

Register the View and ViewModel:

var viewModelLocator = _host.Services.GetRequiredService<IViewModelLocator>();
viewModelLocator.Register<MainView, MainViewModel>();

Show MainView:

var main = _host.Services.GetRequiredService<MainView>();
main.Show();

The correct view model type is resolved:

var viewModelLocator = _host.Services.GetRequiredService<IViewModelLocator>();
var viewModelType = viewModelLocator.ResolveViewModel(typeof(MainView));

This might be where I'm going wrong when registering the View & ViewModel:

services.AddSingleton<MainView>();
services.AddTransient<MainViewModel>();
juicebyjustin
  • 434
  • 7
  • 16
  • 1
    Looking just now I can see the Catel documentation is very _wanting_. Both #1 and #2 of what you seek are possible [here](https://docs.catelproject.com/5.12/introduction/mvvm/introduction-to-services/) and [here](https://docs.catelproject.com/5.12/faq/mvvm/#how-can-i-inject-or-manipulate-the-view-model-of-a-usercontrol) so I would agree with you here. –  Dec 04 '20 at 22:18
  • 1
    Whilst DI can be great I can't help but feel it has no place in MVVM. DI in this case is just an obstruction and attempts to solve a non-existent WPF issue. By having to inject via constructor (instead of via say properties) it's clear that DI promoters don't understand WPF or are at least ignoring WPF Design Mode. When the VM creates the V (because you have no XAML-specified DataContext) both the XAML editor and Designer have no clue how to suggest bindings to your VM. Any typos won't be picked up until runtime. Static code analysis will show a great deal of little-used code –  Dec 04 '20 at 22:53
  • MickyD I am struggling with a similar problem. In a simple .NET 5 WPF program. So I use MVVM, which I am happy with. But DI cause a lot of problems, with the GUI, and xaml at design time. I am kind of wondering if I should keep the DI out of the UI scope, and use it 'just' use it elsewhere? It appears like the tying together of the MVVM and Xaml, is a pain I is just quite attractive from a decoupling point of view and unit testing and acceptance testing. Thanks – kfn Jan 22 '21 at 14:43

1 Answers1

1

Catel uses its own ServiceLocator by default. You can override any aspect of Catel by either implementing your own IServiceLocator / IDependencyResolver.

A simpler way for just vm's is to use a custom IViewModelFactory implementation.

Basically:

  1. To resolve views => IViewLocator
  2. To resolve view models => IViewModelLocator
  3. To create view models => IViewModelFactory
Geert van Horrik
  • 5,689
  • 1
  • 18
  • 32