Using the ViewModelLocator
The ViewModelLocator is used to wire the DataContext of a view to an instance of a ViewModel using a standard naming convention.
The Prism ViewModelLocator has an AutoWireViewModel attached property, that when set to true calls the AutoWireViewModelChanged method in the ViewModelLocationProvider class to resolve the ViewModel for the view, and then set the view’s data context to an instance of that ViewModel. This behavior is on by default: if you don't want that for your view, you need to opt-out.
In the case of WPF, this is only the default behavior when using region navigation and
IDialogService. If you are using view injection, your view will need to opt-in.
Use the AutoWireViewModel attached property as below. Set the value to False to opt-out and True to explicitly opt-in.
<Window x:Class="Demo.Views.MainWindow"
...
xmlns:prism="http://prismlibrary.com/"
prism:ViewModelLocator.AutoWireViewModel="False">
To locate a ViewModel, the ViewModelLocationProvider first attempts to resolve the ViewModel from any mappings that may have been registered by the ViewModelLocationProvider.Register method (See Custom ViewModel Registrations). If the ViewModel cannot be resolved using this approach, the ViewModelLocationProvider falls back to a convention-based approach to resolve the correct ViewModel type.
This convention assumes:
- that ViewModels are in the same assembly as the view types
- that ViewModels are in a
.ViewModelschild namespace - that views are in a
.Viewschild namespace - that ViewModel names correspond with view names and end with "ViewModel."
Note
The ViewModelLocationProvider can be found in the Prism.Mvvm namespace in the Prism.Core NuGet package. The ViewModelLocator can be found in the Prism.Mvvm namespace in the platform specific packages (Prism.WPF, Prism.Forms) NuGet package.
Note
The ViewModelLocator is required, and automatically applied to every View, when developing with Xamarin.Forms as it is responsible for providing the correct instance of the INavigationService to the ViewModel. When developing a Xamarin.Forms app, the ViewModelLocator is opt-out only.
Change the Naming Convention
If your application does not follow the ViewModelLocator default naming convention, you can change the convention to meet the requirements of your application. The ViewModelLocationProvider class provides a static method called SetDefaultViewTypeToViewModelTypeResolver that can be used to provide your own convention for associating views to view models.
To change the ViewModelLocator naming convention, override the ConfigureViewModelLocator method in the App.xaml.cs class. Then provide your custom naming convention logic in the ViewModelLocationProvider.SetDefaultViewTypeToViewModelTypeResolver method.
protected override void ConfigureViewModelLocator()
{
base.ConfigureViewModelLocator();
ViewModelLocationProvider.SetDefaultViewTypeToViewModelTypeResolver((viewType) =>
{
var viewName = viewType.FullName.Replace(".ViewModels.", ".CustomNamespace.");
var viewAssemblyName = viewType.GetTypeInfo().Assembly.FullName;
var viewModelName = $"{viewName}ViewModel, {viewAssemblyName}";
return Type.GetType(viewModelName);
});
}
Custom ViewModel Registrations
There may be instances where your app is following the ViewModelLocator default naming convention, but you have a number of ViewModels that do not follow the convention. Instead of trying to customize the naming convention logic to conditionally meet all your naming requirments, you can register a mapping for a ViewModel to a specific view directly with the ViewModelLocator by using the ViewModelLocationProvider.Register method.
The following examples show the various ways to create a mapping between a view called MainWindow and a ViewModel named CustomViewModel.
Type / Type
ViewModelLocationProvider.Register(typeof(MainWindow).ToString(), typeof(CustomViewModel));
Type / Factory
ViewModelLocationProvider.Register(typeof(MainWindow).ToString(), () => Container.Resolve<CustomViewModel>());
Generic Factory
ViewModelLocationProvider.Register<MainWindow>(() => Container.Resolve<CustomViewModel>());
Generic Type
ViewModelLocationProvider.Register<MainWindow, CustomViewModel>();
Note
Registering your ViewModels directly with the ViewModelLocator is faster than relying on the default naming convention. This is because the naming convention requires the use of reflection, while a custom mapping provides the type directly to the ViewModelLocator.
Important
The viewTypeName parameter must be the fully qualifyied name of the view's Type (Type.ToString()). Otherwise the mapping will fail.
Control how ViewModels are Resolved
By default, the ViewModelLocator will use the DI container you have chosen to create your Prism application to resolve ViewModels. However, if you ever have the need to customize how ViewModels are resolved or change the resolver altogether, you can achieve this by using the ViewModelLocationProvider.SetDefaultViewModelFactory method.
This example shows how you might change the container used for resolving the ViewModel instances.
protected override void ConfigureViewModelLocator()
{
base.ConfigureViewModelLocator();
ViewModelLocationProvider.SetDefaultViewModelFactory((viewModelType) =>
{
return MyAwesomeNewContainer.Resolve(viewModelType);
});
}
This is an example of how you might check the type of the view the ViewModel is being created for, and performing logic to control how the ViewModel is created.
protected override void ConfigureViewModelLocator()
{
base.ConfigureViewModelLocator();
ViewModelLocationProvider.SetDefaultViewModelFactory((view, viewModelType) =>
{
switch (view)
{
case Window window:
//your logic
break;
case UserControl userControl:
//your logic
break;
}
return MyAwesomeNewContainer.Resolve(someNewType);
});
}