Creating a WPF Application using Prism Library and MVVM Architectural Pattern

Introduction 
 
This blog explains how to develop a WPF application using a Prism library and MVVM architectural pattern. No matter how big or complex your app is, this base foundation stays the same for all types of projects. That's why it's very crucial to understand its behavior. We will learn how to make use of UnityContainer and how to achieve modularity in WPF applications using Prism.
 
Why Prism? Prism is a framework for building loosely coupled, maintainable, and testable XAML applications in WPF.
 
Note: There is a project download attached for your reference. The source code is free to use and developed only for learning purposes.
 
Steps
  1. Start Visual Studio, Click on create WPF APP (.Net Framework) : give a name to your app as you desire. As this is a demo project, I have chosen My_First_WPF_App (Refer to the below image.)



  2. Right-click on your project (not the solution) and add a new window into your My_First_WPF_App project. Name your window Shell.xaml. Shell is your Master layout: It's going to load regions for your WPF App. You can delete MainWindow.xaml or can rename as Shell.xaml
    (Refer to the below image.)



  3. Let's begin with Prism's installation: Add Prism.Unity using the Nuget package manager into your shell project. Right-click on the project and click on the Nuget Package manager (Refer to the below image). Then hit install. This will install Prism libraries into your project.



  4. After the successful installation of Prism.unity. Expand your project's references to check if prism libraries are added or not.
    (Refer below image.)



  5. Now that we have an entrypoint - Shell.Xaml, from where we're going to start loading our modules, we need a class to load the shell. For that, we're going to add the class into My_First_WPF_App Project and name it BootStrapper.

  6. Note : Make the  BootStrapper class Public and inherit from UnityBootStapper Class,
    UnityBootStapper class coming from namespace: using Prism.Unity;
    • Override Run() method,
    • Override CreateShell() method,
    • Override InitializeShell() method,
    • Override ConfigureModuleCatalog() method
  7. (Refer below code snippet.)
    1. using System;      
    2. using System.Windows;      
    3. using Prism.Unity;      
    4.       
    5. namespace My_First_WPF_App      
    6. {      
    7.     /// <summary>      
    8.     /// BootStrapper is responsible for loading prism and initializing Shell.      
    9.     /// </summary>      
    10.     [Obsolete]      
    11.     public class BootStrapper : UnityBootstrapper      
    12.     {      
    13.         #region Overridden Methods      
    14.         /// <summary>      
    15.         /// Entry point to the application      
    16.         /// </summary>      
    17.         /// <param name="runWithDefaultConfiguration"></param>      
    18.         public override void Run(bool runWithDefaultConfiguration)      
    19.         {      
    20.             base.Run(runWithDefaultConfiguration);      
    21.         }      
    22.       
    23.         /// <summary>      
    24.         /// Initializes shell.xaml      
    25.         /// </summary>      
    26.         /// <returns></returns>      
    27.         protected override DependencyObject CreateShell()      
    28.         {      
    29.             return Container.TryResolve<Shell>();      
    30.         }      
    31.       
    32.         /// <summary>      
    33.         /// loads the Shell.xaml      
    34.         /// </summary>      
    35.         protected override void InitializeShell()      
    36.         {      
    37.             App.Current.MainWindow = (Window)Shell;      
    38.             App.Current.MainWindow.Show();      
    39.         }      
    40.       
    41.         /// <summary>      
    42.         /// Add view(module) from other assemblies and begins with modularity      
    43.         /// </summary>      
    44.         protected override void ConfigureModuleCatalog()      
    45.         {      
    46.             base.ConfigureModuleCatalog();      
    47.         }      
    48.         #endregion      
    49.     }      
    50. }      
  8. Build your project once to make sure there are no errors so far.

  9. Open App.xaml and delete, StartupUri="MainWindow.xaml" - As your project's default startup window is MainWindow but we've deleted or renamed it. Now we want our app's entry point to be Shell.xaml
    Open the code-behind of App.xaml which is App.xaml.cs and create an object of BootStrapper.
    (Refer bold part of below code snippet.)
    1. using System.Windows;      
    2.       
    3. namespace My_First_WPF_App      
    4. {      
    5.     /// <summary>      
    6.     /// Interaction logic for App.xaml      
    7.     /// </summary>      
    8.     public partial class App : Application      
    9.     {      
    10.         protected override void OnStartup(StartupEventArgs e)      
    11.         {      
    12.             base.OnStartup(e);      
    13.             BootStrapper bootStrapper = new BootStrapper();      
    14.             bootStrapper.Run();      
    15.         }      
    16.     }      
    17. }    
    Run your project and see the magic. Your project will load into the Shell window, now that we've got Shell as entry point.

  10. Now that we have all the control towards Shell.xaml, it's time to add some Modularity to your project.
    1. Go to Shell.xaml
    2. First add the Prism Namespace : xmlns:prism="http://prismlibrary.com/"
    3. Create ItemsControl inside your grid : <ItemsControl prism:RegionManager.RegionName="Shell"/>

      (Refer bold part of below code snippet.)
      1. <Window x:Class="My_First_WPF_App.Shell"      
      2.         xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"      
      3.         xmlns:d="http://schemas.microsoft.com/expression/blend/2008"      
      4.         xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"      
      5.         xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"      
      6.         mc:Ignorable="d"      
      7.         xmlns:prism="http://prismlibrary.com/"      
      8.         Title="Shell" Height="450" Width="800">      
      9.     <Grid>      
      10.         <ItemsControl prism:RegionManager.RegionName="Shell"/>      
      11.     </Grid>      
      12. </Window>  
  11. Now that we've set our main project, it's time to add some modules. As there are 3 basic modules of 3 -Tier Architecture. This is a demo project so we will create only one Presentation module which is Class Library (DLL). Right-click on Solution and add DLL to your Solution file. Name your DLL Presentation.
    (Refer below image.)



  12. Let's create View and ViewModels folders in this DLL. (It's the same way, right-click on presentation, Add new folder from submenu, rename as View. Follow same for ViewModel)
    • Add our first UserControl.xaml into View folder and name it WelcomePageView.Xaml(WPF).
    • In the same way, let's add C# class file into ViewModel folder and name it WelcomePageViewModel.cs
  13. Add Prism into your newly created Presentation.dll, follow step 3.

  14. Open WelcomePageView : Add namespaces, and set AutoWireViewModel to true inside UserControl tag
    (Refer bold part of below code snippet.)
    1. <UserControl x:Class="Presentation.View.WelcomePageView"      
    2.              xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"                  
    3.              xmlns:d="http://schemas.microsoft.com/expression/blend/2008"      
    4.              xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"      
    5.              xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"      
    6.              xmlns:prism="http://prismlibrary.com/"    
    7.              prism:ViewModelLocator.AutoWireViewModel="True"    
    8.              mc:Ignorable="d"                 
    9.              d:DesignHeight="450" d:DesignWidth="800">   
  15. Now we need the Module Locator, so add a C# class and name it as ModuleLocators.cs inside Presentation.dll Project
    1. Inherit class from Imodule interface from using Prism.Modularity;
    2. Implement Interface
    3. Create Instance of IRegionManager
    4. Create Parameterized Constructor and assign to instance
    5. Override OnInitialized method , can leave the RegisterTypes empty for now.
      (Refer below code snippet.)
      1. using Prism.Ioc;        
      2. using Prism.Modularity;        
      3. using Prism.Regions;        
      4.         
      5. namespace Presentation        
      6. {        
      7.     /// <summary>        
      8.     /// Responsible for mapping modules        
      9.     /// </summary>        
      10.     public class ModuleLocators : IModule        
      11.     {        
      12.         #region private properties        
      13.         /// <summary>        
      14.         /// Instance of IRegionManager        
      15.         /// </summary>        
      16.         private IRegionManager _regionManager;        
      17.      
      18.         #endregion        
      19.      
      20.         #region Constructor        
      21.         /// <summary>        
      22.         /// parameterized constructor initializes IRegionManager        
      23.         /// </summary>        
      24.         /// <param name="regionManager"></param>        
      25.         public ModuleLocators(IRegionManager regionManager)        
      26.         {        
      27.             _regionManager = regionManager;        
      28.         }        
      29.         #endregion        
      30.      
      31.         #region Interface methods        
      32.         /// <summary>        
      33.         /// Initializes Welcome page of your application.        
      34.         /// </summary>        
      35.         /// <param name="containerProvider"></param>        
      36.         public void OnInitialized(IContainerProvider containerProvider)        
      37.         {        
      38.             _regionManager.RegisterViewWithRegion("Shell"typeof(ModuleLocators));  //ModuleLocators is added for testing purpose,     
      39. //later we'll replace it with WelcomePageView      
      40.         }        
      41.         
      42.         /// <summary>        
      43.         /// RegisterTypes used to register modules        
      44.         /// </summary>        
      45.         /// <param name="containerRegistry"></param>        
      46.         public void RegisterTypes(IContainerRegistry containerRegistry)        
      47.         {        
      48.         }        
      49.         #endregion        
      50.     }        
      51. }     
  16. Let's add the presentation module's reference into (My_First_WPF_App) project. Right click on references of My_First_WPF_App and click on add references, then go to projects and select Presentation. Hit OK.
    (Refer to the image below.)



  17. Now its time to tell BootStrapper which module it should look for. Open BootStapper.cs, Inside ConfigureModuleCatalog.
    (Refer to the bold part of the below code snippet.)
    1. using System;      
    2. using System.Windows;      
    3. using Prism.Unity;      
    4.       
    5. namespace My_First_WPF_App      
    6. {      
    7.     /// <summary>      
    8.     /// BootStrapper is responsible for loading prism and initializing Shell.      
    9.     /// </summary>      
    10.     [Obsolete]      
    11.     public class BootStrapper : UnityBootstrapper      
    12.     {      
    13.         #region Overridden Methods      
    14.         /// <summary>      
    15.         /// Entry point to the application      
    16.         /// </summary>      
    17.         /// <param name="runWithDefaultConfiguration"></param>      
    18.         public override void Run(bool runWithDefaultConfiguration)      
    19.         {      
    20.             base.Run(runWithDefaultConfiguration);      
    21.         }      
    22.       
    23.         /// <summary>      
    24.         /// Initializes shell.xaml      
    25.         /// </summary>      
    26.         /// <returns></returns>      
    27.         protected override DependencyObject CreateShell()      
    28.         {      
    29.             return Container.TryResolve<Shell>();      
    30.         }      
    31.       
    32.         /// <summary>      
    33.         /// loads the Shell.xaml      
    34.         /// </summary>      
    35.         protected override void InitializeShell()      
    36.         {      
    37.             App.Current.MainWindow = (Window)Shell;      
    38.             App.Current.MainWindow.Show();      
    39.         }      
    40.       
    41.         /// <summary>      
    42.         /// Add view(module) from other assemblies and begins with modularity      
    43.         /// </summary>      
    44.         protected override void ConfigureModuleCatalog()      
    45.         {      
    46.             base.ConfigureModuleCatalog();      
    47.             Type ModuleLocatorType = typeof(Presentation.ModuleLocators);      
    48.             ModuleCatalog.AddModule(new Prism.Modularity.ModuleInfo      
    49.             {      
    50.                 ModuleName = ModuleLocatorType.Name,      
    51.                 ModuleType = ModuleLocatorType.AssemblyQualifiedName      
    52.             });      
    53.         }      
    54.         #endregion      
    55.     }      
    56. }    
  18. Now go to your ModuleLocators class of Presentation module. On the inside method, OnInitialized(), change type from NewlyCreatedView to WelcomePageView.
    (Refer to the bold part of the below code snippet.)
    1. using Prism.Ioc;      
    2. using Prism.Modularity;      
    3. using Prism.Regions;      
    4.       
    5. namespace Presentation      
    6. {      
    7.     /// <summary>      
    8.     /// Responsible for mapping modules      
    9.     /// </summary>      
    10.     public class ModuleLocators : IModule      
    11.     {      
    12.         #region properties      
    13.         /// <summary>      
    14.         /// Instance of IRegionManager      
    15.         /// </summary>      
    16.         private IRegionManager _regionManager;      
    17.    
    18.         #endregion      
    19.    
    20.         #region Constructor      
    21.         /// <summary>      
    22.         /// parameterized constructor initializes IRegionManager      
    23.         /// </summary>      
    24.         /// <param name="regionManager"></param>      
    25.         public ModuleLocators(IRegionManager regionManager)      
    26.         {      
    27.             _regionManager = regionManager;      
    28.         }      
    29.         #endregion      
    30.    
    31.         #region Interface methods      
    32.         /// <summary>      
    33.         /// Initializes Welcome page of your application.      
    34.         /// </summary>      
    35.         /// <param name="containerProvider"></param>      
    36.         public void OnInitialized(IContainerProvider containerProvider)      
    37.         {      
    38.             _regionManager.RegisterViewWithRegion("Shell"typeof(View.WelcomePageView));      
    39.         }      
    40.       
    41.         /// <summary>      
    42.         /// RegisterTypes used to register modules      
    43.         /// </summary>      
    44.         /// <param name="containerRegistry"></param>      
    45.         public void RegisterTypes(IContainerRegistry containerRegistry)      
    46.         {      
    47.         }      
    48.         #endregion      
    49.     }      
    50. }  
  19. Add a Textblock inside WelcomePageView to see if it's working properly.
    (Refer to the bold part of the below code snippet.)
    1. <UserControl x:Class="Presentation.View.WelcomePageView"      
    2.              xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"      
    3.              xmlns:prism="http://prismlibrary.com/"      
    4.              xmlns:d="http://schemas.microsoft.com/expression/blend/2008"      
    5.              xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"      
    6.              xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"      
    7.              mc:Ignorable="d"      
    8.              prism:ViewModelLocator.AutoWireViewModel="True"      
    9.              d:DesignHeight="450" d:DesignWidth="800">      
    10.     <Grid>      
    11.     <TextBlock Text="You successfully have configured Prism into your APP" />      
    12.     </Grid>      
    13. </UserControl> 
  20. Build and run your project. You'll get following output screen:
    (Refer to the image below.)



  21. Until now, we've added Prism into our project and we've finally achieved modularity. One final step left is having view communicate with viewmodel using MVVM pattern. We will achieve that with DataContext.

  22. Let's add one more textblock into our WelcomePageView and bind it using a string property from our WelcomePageViewModel.
    (Refer to the bold part of the below code snippet.)
    1. <UserControl x:Class="Presentation.View.WelcomePageView"      
    2.              xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"      
    3.              xmlns:prism="http://prismlibrary.com/"      
    4.              xmlns:d="http://schemas.microsoft.com/expression/blend/2008"      
    5.              xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"      
    6.              xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"      
    7.              mc:Ignorable="d"      
    8.              prism:ViewModelLocator.AutoWireViewModel="True"      
    9.              d:DesignHeight="450" d:DesignWidth="800">      
    10.     <Grid>      
    11.         <Grid.RowDefinitions>      
    12.             <RowDefinition/>      
    13.             <RowDefinition/>      
    14.         </Grid.RowDefinitions>      
    15.         <TextBlock Text="You successfully have configured Prism into your APP" />      
    16.         <TextBlock Text="{Binding ImGoodByeText}" Grid.Row="1"/>      
    17.     </Grid>      
    18. </UserControl>    
    1. using System;      
    2.       
    3. namespace Presentation.ViewModel      
    4. {      
    5.     /// <summary>      
    6.     /// View Model of WelcomePage, responsible for logic for respected view.      
    7.     /// </summary>      
    8.    public class WelcomePageViewModel      
    9.     {      
    10.         #region Properties      
    11.             /// <summary>      
    12.             /// This string property will have default text for demo purpose.    
    13.             /// </summary>      
    14.             private string _imGoodByeText = "This is binded from WelcomePageViewModel, Thank you for being part of this Blog!";      
    15.             /// <summary>      
    16.             /// This string property will be binded with Textblock on view       
    17.             /// </summary>      
    18.             public string ImGoodByeText      
    19.             {      
    20.                 get { return _imGoodByeText; }      
    21.                 set { _imGoodByeText = value; }      
    22.             }      
    23.         #endregion      
    24.       
    25.     }      
    26. }   
  23. And now open code behind WelcomePageView, so that we can set datacontext property from constructor.
    1. using Presentation.ViewModel;      
    2. using System.Windows.Controls;      
    3.       
    4. namespace Presentation.View      
    5. {      
    6.     /// <summary>      
    7.     /// Interaction logic for WelcomePageView.xaml      
    8.     /// </summary>      
    9.     public partial class WelcomePageView : UserControl      
    10.     {      
    11.         public WelcomePageView()      
    12.         {      
    13.             InitializeComponent();      
    14.             this.DataContext = new WelcomePageViewModel();      
    15.         }      
    16.     }      
    17. }   
  24. Now build and run your project, you'll get final output as below image.
    (Refer to the image below.)


Thank you so much for visiting this blog, I hope you were helped by this. If you have any queries, please connect with me.

Have a good day :)