Unable to register View to ViewModel manually using Prism.Mvvm.ViewModelLocationProvider

Viewed 1438

Folder structure -

Project Named 'Home'
|> Views > HomeView.xaml
|> ViewModels > HomeViewModel.cs
|> HomeModule.cs (an IModule class)

HomeView.XAML (Note: AutoWireViewModel is set to FALSE)

<UserControl
    x:Class="Tally.Sync.Home.Views.HomeView"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:local="clr-namespace:Tally.Sync.Home.Views"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    xmlns:prism="http://prismlibrary.com/"
    d:DesignHeight="450"
    d:DesignWidth="800"
    prism:ViewModelLocator.AutoWireViewModel="False"
    mc:Ignorable="d">
    <Grid>
        <TextBlock
            HorizontalAlignment="Center"
            VerticalAlignment="Center"
            FontSize="28"
            Text="{Binding Message}" />
    </Grid>
</UserControl>

HomeViewModel.cs

public class HomeViewModel : BindableBase
{
    private string _message = "Hi There!";
    public string Message
    {
        get { return _message; }
        set { SetProperty(ref _message, value); }
    }

    public HomeViewModel()
    {

    }
}

HomeModule.cs

public class HomeModule : IModule
{
    private readonly IRegionManager _regionManager;

    public HomeModule(IRegionManager regionManager)
    {
        _regionManager = regionManager;
    }

    public void OnInitialized(IContainerProvider containerProvider)
    {
        _regionManager.RegisterViewWithRegion("ContentRegion", typeof(HomeView));
    }

    public void RegisterTypes(IContainerRegistry containerRegistry)
    {
        ViewModelLocationProvider.Register<HomeView, HomeViewModel>();
    }
}

As you can see I am registering the HomeView & HomeViewModel with the ViewModelLocationProvider. But this doesn't work. My code is running as expected when the AutoWireViewModel is set to True

What am I doing wrong? I know I can auto wire it, but I am trying to learn Prism and one of videos by Brian Lagunas mentions wiring manually is faster as reflection won't be required.

1 Answers

When you register views and view models manually to the view model locator, you still have to enable auto-wiring in the view model, it will just change how the ViewModelLocator resolves the view and its view model. Setting False will disable it, so it does not resolve anything.

prism:ViewModelLocator.AutoWireViewModel="True"

As you can see from the reference source for ViewModelLocationProvider, registered views will be checked first when resolving the view model. If there are no registrations, the fallback to resolving with the naming convention via reflection will be used.

public static void AutoWireViewModelChanged(object view, Action<object, object> setDataContextCallback)
{
   object viewModel = GetViewModelForView(view);

   if (viewModel == null)
   {
      // Try to resolve the view model via regsitrations
      var viewModelType = GetViewModelTypeForView(view.GetType());

      // If views and view models are not registerd, fallback to reflection
      if (viewModelType == null)
         viewModelType = _defaultViewTypeToViewModelTypeResolver(view.GetType());

      //...
   }

   // ...
}

As the ViewModelLocator will resolve the view both via registration or the naming convention fallback, you did not notice a difference. If you rename your HomeViewModel to HomeFooBar or anything else that does not fit the naming convention, the fallback will fail and you will see that it works as described above.

[...] wiring manually is faster as reflection won't be required.

I think that there are many misunderstandings concerning reflection. In this case with a few views you will not even notice any difference and it is much more convenient. Do not optimize prematurely.

Related