Search code examples
wpfmvvmunity-containerprism

Switching views in the same module for WPF Prism MVVM


I am trying to understand how to switch views and its viewmodels in a wpf mvvm application which uses prism and unity. I put something together from a tutorial but have additional question bec a few things dont seem right. What I have so far is a WPF application with a shell.xaml window that has section placeholders using prism regions. In addition, I have a bootstrapper class that register modules which will fill in the different regions in the shell.xaml window. In the modules which are class libraries I have the initialize function setting the views and viewmodels. I have only two regions in this application the navigation and the workspace. I have 2 buttons on the navigation and they change the view in the workspace. The workspace views are in their own modules. So at this point each workspace view has its own class library module. In a big application this seems unreasonable of having each view have its own class library. I wanted to know how can I have multiple views and viewmodels in one class library and swap them in and out. If you have a good step by step tutorial that would be great.


Solution

  • I know this is 4 years late, but I ll give an answer anyway. First thing you do is add the Views you need to the Views folder and add their corresponding ViewModels in the ViewModels folder so that you have a structure as described below :

    ViewModels

    • ViewModelA
    • ViewModelB

    Views

    • ViewA
    • ViewB

    The ViewModels and their corresponding view could look something like this :

    ViewModelA

    using System;
    
    namespace SomeApp.DemoModule.ViewModels
    {
        public class ViewModelA : INavigationAware
        {
            public ViewModelA(IUnityContainer container, IRegionManager regionManager, IEventAggregator eventAggregator)
            {
                this.container = container;
                this.regionManager = regionManager;
                this.eventAggregator = eventAggregator;
            }
    
            public bool IsNavigationTarget(NavigationContext navigationContext)
            {
                return true;
            }
    
            public void OnNavigatedFrom(NavigationContext navigationContext)
            {
            }
    
            public void OnNavigatedTo(NavigationContext navigationContext)
            {
                //Do stuff here
    
                //For navigation back
                navigationService = navigationContext.NavigationService;
            }
    
            #region Executes
            /// <summary>
            /// Command when ViewB button clicked
            /// </summary>
            public void Execute_ViewBCommand()
            {
                regionManager.RequestNavigate("REGIONNAME_HERE", new Uri("ViewB", UriKind.Relative));
            }
    

    ViewA

    <UserControl x:Class="DemoModule.Views.ViewA"
             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:local="clr-namespace:ViewInjection.Views"
             mc:Ignorable="d" 
             d:DesignHeight="300" d:DesignWidth="300">
    <Grid>
      <Button Content="VIEWB" FontSize="38" Command="{Binding ViewBCommand}"></Button>
    </Grid>
    

    ViewA.Xaml.cs

       namespace SomeApp.DemoModule.Views
    {
        /// <summary>
        /// Interaction logic for ViewA.xaml
        /// </summary>
        public partial class ViewA : UserControl
        {
            public ViewA(ViewModelA model)
            {
                InitializeComponent();
                this.DataContext = model;
            }
        }
    }
    

    ViewModelB

        using System;
    
    namespace SomeApp.DemoModule.ViewModels
    {
        public class ViewModelB : INavigationAware
        {
            public ViewModelB(IUnityContainer container, IRegionManager regionManager, IEventAggregator eventAggregator)
            {
                this.container = container;
                this.regionManager = regionManager;
                this.eventAggregator = eventAggregator;
            }
    
            public bool IsNavigationTarget(NavigationContext navigationContext)
            {
                return true;
            }
    
            public void OnNavigatedFrom(NavigationContext navigationContext)
            {
            }
    
            public void OnNavigatedTo(NavigationContext navigationContext)
            {
                //Do stuff here
    
                //For navigation back
                navigationService = navigationContext.NavigationService;
            }
    
            #region Executes
            /// <summary>
            /// Command when ViewA button clicked
            /// </summary>
            public void Execute_ViewACommand()
            {
                regionManager.RequestNavigate("REGIONNAME_HERE", new Uri("ViewA", UriKind.Relative));
            }
    

    ViewB

     <UserControl x:Class="DemoModule.Views.ViewB"
             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" 
             mc:Ignorable="d" 
             d:DesignHeight="300" d:DesignWidth="300">
    <Grid>
      <Button Content="VIEWA" FontSize="38" Command="{Binding ViewACommand}"></Button>
    </Grid>
    

    ViewB.Xaml.cs

       namespace SomeApp.DemoModule.Views
    {
        /// <summary>
        /// Interaction logic for ViewB.xaml
        /// </summary>
        public partial class ViewB : UserControl
        {
            public ViewB(ViewModelB model)
            {
                InitializeComponent();
                this.DataContext = model;
            }
        }
    }
    

    You can register your views in several ways, we use a DemoModuleInit class in the project root that registers the view :

    DemoModuleInit

    public class DemoModuleInit : IModule
    {
        private IRegionManager regionManager;
    
        /// <summary>
        /// Bind your interfaces, subscribe to events, do stuff that needs to be done on intialization of module
        /// </summary>
        public void OnInitialized(IContainerProvider containerProvider)
        {
            // Setup Event listeners etc...
            regionManager = containerProvider.Resolve<IRegionManager>();
        }
    
        /// <summary>
        /// Register your views for this Module
        /// </summary>
        public void RegisterTypes(IContainerRegistry containerRegistry)
        {
            containerRegistry.RegisterForNavigation<ViewA>();
            containerRegistry.RegisterForNavigation<ViewB>();
        }
    

    If implemented correctly you should be able to navigate from ViewA to ViewB and back within the same module For more information on Prism check out : Prsim on GitHub