Home > Mobile >  View is not found
View is not found

Time:07-09

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 UserControls 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.

Custom view model type resolver code.

At first, the AutoWireViewModel is set to true:

AutoWireViewModel declaration in XAML.

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).

Solution explorer showing the SelectDataChangeView and its view model SelectDataChangeVM within the same folder.

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:

  1. Rename your view model to fit the convention, e.g.: SelectDataChangeViewModel.

  2. 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:

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.

  • Related