I have a problem with a binding of the new UserControl
in WPF, using MVVM and Prism (the view name is SelectDataChangeView
).
So, I have a lot of UserControl
s which work, but when I'm trying to configure new one, I can't force the application to create & bind it to the ViewModel. The problem is, that the ViewModelLocationProvider.SetDefaultViewTypeToViewModelTypeResolver
does not find the new view, so the constructor of the view does not start and later the VM ist not registered.
In other words, the viewType
parameter is never set to SelectDataChangeView
, so the VM is not registered. As you can see, I've also tried to register the VM manually, but it still does not help.
At first, the AutoWireViewModel
is set to true
:
The ViewModel exists. What I can add, the new View is a copy of SelectPackagesView
, which works perfectly. Of course the namespaces, and class names have been changed and double checked (moving the VM to the ViewModels folder did not help).
When I configured the new UserControl
as a region, then View has been created and mapped to the VM.
CodePudding user response:
The default convention for mapping view names to view model names is the suffix ViewModel
.
This convention assumes:
- that ViewModels are in the same assembly as the view types
- that ViewModels are in a .ViewModels child namespace
- that views are in a .Views child namespace
- that ViewModel names correspond with view names and end with "ViewModel."
The view name SelectDataChangeView
will be mapped to SelectDataChangeViewModel
. Consequently, Prism will not find the view model, since its name actually is SelectDataChangeVM
. See the implementation on GitHub:
static Func<Type, Type> _defaultViewTypeToViewModelTypeResolver =
viewType =>
{
var viewName = viewType.FullName;
viewName = viewName.Replace(".Views.", ".ViewModels.");
var viewAssemblyName = viewType.GetTypeInfo().Assembly.FullName;
var suffix = viewName.EndsWith("View") ? "Model" : "ViewModel";
var viewModelName = String.Format(CultureInfo.InvariantCulture, "{0}{1}, {2}", viewName, suffix, viewAssemblyName);
return Type.GetType(viewModelName);
};
You have two options to resolve the issue:
Rename your view model to fit the convention, e.g.:
SelectDataChangeViewModel
.Override the default mapping behavior in your application:
protected override void ConfigureViewModelLocator() { base.ConfigureViewModelLocator(); ViewModelLocationProvider.SetDefaultViewTypeToViewModelTypeResolver(viewType => { var viewName = viewType.FullName; viewName = viewName.Replace(".Views.", ".ViewModels."); var viewAssemblyName = viewType.GetTypeInfo().Assembly.FullName; if (viewName.EndsWith("View")) viewName = viewName.Substring(0, viewName.Length - 4); var viewModelName = string.Format(CultureInfo.InvariantCulture, "{0}{1}, {2}", viewName, "VM", viewAssemblyName); return Type.GetType(viewModelName); }); }
Your custom override probably does not work for a different reason, which might also explain why your non-default naming convention supposedly works, e.g:
- It returns the wrong type.
- You explicitly register view models for the locator, see Custom ViewModel Registrations.
- You resolve the view models with a custom factory, see Control how ViewModels are Resolved.
CodePudding user response:
I've also tried to register the VM manually
You do that when registering for navigation, i.e.
containerRegistry.RegisterForNavigation<SelectDataChangeView, SelectDataChangeVM>();
Registering with the ViewModelLocationProvider
alone is not enough.