Forum Discussion
How to decouple views from view models using CommunityToolKit.mvvm
I am writing my first MVVM app using CommunityTookit.mvvm. I am using as reference the Micrsoft Learning link https://learn.microsoft.com/en-us/dotnet/communitytoolkit/mvvm/ioc. This link shows the setting of the viewmodel to the view DataContext using the following statement in the view's .cs file:
this.DataContext = App.Current.Services.GetService<ContactsViewModel>();
The problem with this as I see it is that this statement couples the view to the view model, in this case ContactsViewModel. This means that in another app the view cannot be used with another viewmodel without modifying the view, i.e. changing ContactsViewModel above to another viewmodel type. This means that the view cannot be stored in a common library that is shared among different apps.
There is a C# Corner example with the older MVVM TookKit that solved this problem using a ViewModelLocator class. This project is found https://www.c-sharpcorner.com/article/getting-started-with-mvvm-light-with-wpf/. The solution is to put the following code in the view's XAML file:
DataContext="{Binding Main, Source={StaticResource Locator}}"
The source object for the binding is found by looking for a ResourceDictionary that is in the scope of the view and which has an entry whose key is "Locator". In app.xaml which by definition is always in scope we have:
<Application.Resources>
<ResourceDictionary>
<vm:ViewModelLocator x:Key="Locator" d:IsDataSource="True" />
</ResourceDictionary>
</Application.Resources>
The Dictionary element with key "Locator" is an object of type ViewModelLocator. In the ViewModelLocator class there is a Main property that always returns an instance of MainViewModel:
public MainViewModel Main
{
get
{
return ServiceLocator.Current.GetInstance<MainViewModel>();
}
}
In our example, the view's DataContext binds to the Main property of the ViewModelLocator object. The value of the Main property is a MainViewModel object and this becomes the DataContext of the view.
We can now in a different app re-use the view without changing it. All we have to do in the next app is to create a different ViewModelLocator object that specifies a different viewmodel in its Main property. The view is now completely decoupled from the view model.
My question is, how would we de-couple the view from the view model using the CommunityToolkit.Mvvm? Do we also use a ViewModelLocator class? Is there a more elegant way with dependency injection?
Another question I have is, suppose we want to use in one app the same view twice with different view models. An example of where we might want to do this is if we had a view that displayed a chart. It is conceivable that we might want to have more than one view model display its data using the same chart view. I cannot see how to do this in either of the above Microsoft or C# Corner examples.