Search code examples
c#wpfprism

Class Library View not binding to ViewModel for WPF Prism Application


In the last few days I've been trying to learn and setup a demo WPF Prism App which uses Regions. I have 3 Projects within my solution and I'm having an issue whereby a View and ViewModel contained within the "PrismSample.UX" Class Library project will not bind. Below is my code for each project that I believe are relevant to my issue, any help on pointing me in the right direction would be greatly appreciated.

PrismSample (WPF App ".NET Framework")

Shell.xaml

<Window x:Class="PrismSample.Shell"
        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:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:prism="http://prismlibrary.com/"
        xmlns:common="clr-namespace:PrismSample.Common;assembly=PrismSample.Common"
        mc:Ignorable="d"
        Title="MainWindow" Height="450" Width="800">
    <Grid>
        <ContentControl prism:RegionManager.RegionName="{x:Static common:RegionNames.ContentRegion}" />
    </Grid>
</Window>

App.xaml.cs

using System.Windows;
using Prism.Ioc;
using Prism.Unity;
using Prism.Modularity;
using PrismSample.UX;

namespace PrismSample
{
    public partial class App : PrismApplication
    {
        protected override Window CreateShell()
        {
            return Container.Resolve<Shell>();
        }

        protected override void RegisterTypes(IContainerRegistry containerRegistry)
        {
         
        }

        protected override void ConfigureModuleCatalog(IModuleCatalog moduleCatalog)
        {
            moduleCatalog.AddModule<UXModule>();
        }
    }
}

PrismSample.Common (Class Library)

RegionNames.cs

namespace PrismSample.Common
{
    public static class RegionNames
    {
        public const string ContentRegion = "ContentRegion";
    }
}

PrismSample.UX (Class Library)

UXModule.cs

using PrismSample.Common;
using Prism.Ioc;
using Prism.Modularity;
using Prism.Regions;
using PrismSample.UX.Views;

namespace PrismSample.UX
{
    public class UXModule : IModule
    {
        public void OnInitialized(IContainerProvider containerProvider)
        {
            var regionManager = containerProvider.Resolve<IRegionManager>();
            regionManager.RequestNavigate(RegionNames.ContentRegion, nameof(UsersView));
        }

        public void RegisterTypes(IContainerRegistry containerRegistry)
        {
            containerRegistry.RegisterForNavigation<UsersView>();
        }
    }
}

Views/Users.xaml

<UserControl x:Class="PrismSample.UX.Views.UsersView"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
             xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
             xmlns:prism="http://prismlibrary.com/"
             prism:ViewModelLocator.AutoWireViewModel="True"
             mc:Ignorable="d" 
             d:DesignHeight="450" d:DesignWidth="800">
    <Grid>
        <TextBlock 
            Text="{Binding PageName}" 
            FontSize="24"
            HorizontalAlignment="Center"/>
    </Grid>
</UserControl>

ViewModels/UsersViewModel.cs

using Prism.Regions;

namespace PrismSample.ViewModels.UX
{
    public class UsersViewModel : ViewModelBase
    {
        public string PageName { get; set; } = "Users";

        public UsersViewModel(IRegionManager regionManager) :
                              base(regionManager)
        {
        }
    }
}

ViewModels/ViewModelBase.cs

using Prism.Mvvm;
using Prism.Regions;

namespace PrismSample.ViewModels.UX
{
    public class ViewModelBase : BindableBase, INavigationAware
    {
        protected IRegionManager RegionManager { get; }

        public ViewModelBase(IRegionManager regionManager)
        {
            RegionManager = regionManager;
        }

        public virtual bool IsNavigationTarget(NavigationContext navigationContext)
        {
            return true;
        }

        public virtual void OnNavigatedFrom(NavigationContext navigationContext)
        {

        }

        public virtual void OnNavigatedTo(NavigationContext navigationContext)
        {
            
        }
    }
}

Solution

  • namespace PrismSample.ViewModels.UX

    it's the other way round for the standard convention:

    namespace PrismSample.UX.Views
    

    and

    namespace PrismSample.UX.ViewModels
    

    Or you register both together without relying on automatic discovery:

    containerRegistry.RegisterForNavigation<UsersView, UsersViewModel>();
    

    Or you change the convention (use ViewModelLocationProvider.SetDefaultViewTypeToViewModelTypeResolver)...