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
- 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.)
- 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.)
- 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.
- After the successful installation of Prism.unity. Expand your project's references to check if prism libraries are added or not.
(Refer below image.)
- 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.
- 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
-
(Refer below code snippet.)
- using System;
- using System.Windows;
- using Prism.Unity;
-
- namespace My_First_WPF_App
- {
-
-
-
- [Obsolete]
- public class BootStrapper : UnityBootstrapper
- {
- #region Overridden Methods
-
-
-
-
- public override void Run(bool runWithDefaultConfiguration)
- {
- base.Run(runWithDefaultConfiguration);
- }
-
-
-
-
-
- protected override DependencyObject CreateShell()
- {
- return Container.TryResolve<Shell>();
- }
-
-
-
-
- protected override void InitializeShell()
- {
- App.Current.MainWindow = (Window)Shell;
- App.Current.MainWindow.Show();
- }
-
-
-
-
- protected override void ConfigureModuleCatalog()
- {
- base.ConfigureModuleCatalog();
- }
- #endregion
- }
- }
- Build your project once to make sure there are no errors so far.
- 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.)
- using System.Windows;
-
- namespace My_First_WPF_App
- {
-
-
-
- public partial class App : Application
- {
- protected override void OnStartup(StartupEventArgs e)
- {
- base.OnStartup(e);
- BootStrapper bootStrapper = new BootStrapper();
- bootStrapper.Run();
- }
- }
- }
Run your project and see the magic. Your project will load into the Shell window, now that we've got Shell as entry point.
- Now that we have all the control towards Shell.xaml, it's time to add some Modularity to your project.
- Go to Shell.xaml
- First add the Prism Namespace : xmlns:prism="http://prismlibrary.com/"
- Create ItemsControl inside your grid : <ItemsControl prism:RegionManager.RegionName="Shell"/>
(Refer bold part of below code snippet.)
- <Window x:Class="My_First_WPF_App.Shell"
- xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
- xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
- xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
- xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
- mc:Ignorable="d"
- xmlns:prism="http://prismlibrary.com/"
- Title="Shell" Height="450" Width="800">
- <Grid>
- <ItemsControl prism:RegionManager.RegionName="Shell"/>
- </Grid>
- </Window>
- 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.)
- 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
- Add Prism into your newly created Presentation.dll, follow step 3.
- Open WelcomePageView : Add namespaces, and set AutoWireViewModel to true inside UserControl tag
(Refer bold part of below code snippet.)
- <UserControl x:Class="Presentation.View.WelcomePageView"
- xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
- xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
- xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
- xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
- xmlns:prism="http://prismlibrary.com/"
- prism:ViewModelLocator.AutoWireViewModel="True"
- mc:Ignorable="d"
- d:DesignHeight="450" d:DesignWidth="800">
- Now we need the Module Locator, so add a C# class and name it as ModuleLocators.cs inside Presentation.dll Project
- Inherit class from Imodule interface from using Prism.Modularity;
- Implement Interface
- Create Instance of IRegionManager
- Create Parameterized Constructor and assign to instance
- Override OnInitialized method , can leave the RegisterTypes empty for now.
(Refer below code snippet.)
- using Prism.Ioc;
- using Prism.Modularity;
- using Prism.Regions;
-
- namespace Presentation
- {
-
-
-
- public class ModuleLocators : IModule
- {
- #region private properties
-
-
-
- private IRegionManager _regionManager;
-
- #endregion
-
- #region Constructor
-
-
-
-
- public ModuleLocators(IRegionManager regionManager)
- {
- _regionManager = regionManager;
- }
- #endregion
-
- #region Interface methods
-
-
-
-
- public void OnInitialized(IContainerProvider containerProvider)
- {
- _regionManager.RegisterViewWithRegion("Shell", typeof(ModuleLocators));
-
- }
-
-
-
-
-
- public void RegisterTypes(IContainerRegistry containerRegistry)
- {
- }
- #endregion
- }
- }
- 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.)
- 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.)
- using System;
- using System.Windows;
- using Prism.Unity;
-
- namespace My_First_WPF_App
- {
-
-
-
- [Obsolete]
- public class BootStrapper : UnityBootstrapper
- {
- #region Overridden Methods
-
-
-
-
- public override void Run(bool runWithDefaultConfiguration)
- {
- base.Run(runWithDefaultConfiguration);
- }
-
-
-
-
-
- protected override DependencyObject CreateShell()
- {
- return Container.TryResolve<Shell>();
- }
-
-
-
-
- protected override void InitializeShell()
- {
- App.Current.MainWindow = (Window)Shell;
- App.Current.MainWindow.Show();
- }
-
-
-
-
- protected override void ConfigureModuleCatalog()
- {
- base.ConfigureModuleCatalog();
- Type ModuleLocatorType = typeof(Presentation.ModuleLocators);
- ModuleCatalog.AddModule(new Prism.Modularity.ModuleInfo
- {
- ModuleName = ModuleLocatorType.Name,
- ModuleType = ModuleLocatorType.AssemblyQualifiedName
- });
- }
- #endregion
- }
- }
- 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.)
- using Prism.Ioc;
- using Prism.Modularity;
- using Prism.Regions;
-
- namespace Presentation
- {
-
-
-
- public class ModuleLocators : IModule
- {
- #region properties
-
-
-
- private IRegionManager _regionManager;
-
- #endregion
-
- #region Constructor
-
-
-
-
- public ModuleLocators(IRegionManager regionManager)
- {
- _regionManager = regionManager;
- }
- #endregion
-
- #region Interface methods
-
-
-
-
- public void OnInitialized(IContainerProvider containerProvider)
- {
- _regionManager.RegisterViewWithRegion("Shell", typeof(View.WelcomePageView));
- }
-
-
-
-
-
- public void RegisterTypes(IContainerRegistry containerRegistry)
- {
- }
- #endregion
- }
- }
- Add a Textblock inside WelcomePageView to see if it's working properly.
(Refer to the bold part of the below code snippet.)
- <UserControl x:Class="Presentation.View.WelcomePageView"
- xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
- xmlns:prism="http://prismlibrary.com/"
- xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
- xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
- xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
- mc:Ignorable="d"
- prism:ViewModelLocator.AutoWireViewModel="True"
- d:DesignHeight="450" d:DesignWidth="800">
- <Grid>
- <TextBlock Text="You successfully have configured Prism into your APP" />
- </Grid>
- </UserControl>
- Build and run your project. You'll get following output screen:
(Refer to the image below.)
- 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.
- 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.)
- <UserControl x:Class="Presentation.View.WelcomePageView"
- xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
- xmlns:prism="http://prismlibrary.com/"
- xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
- xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
- xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
- mc:Ignorable="d"
- prism:ViewModelLocator.AutoWireViewModel="True"
- d:DesignHeight="450" d:DesignWidth="800">
- <Grid>
- <Grid.RowDefinitions>
- <RowDefinition/>
- <RowDefinition/>
- </Grid.RowDefinitions>
- <TextBlock Text="You successfully have configured Prism into your APP" />
- <TextBlock Text="{Binding ImGoodByeText}" Grid.Row="1"/>
- </Grid>
- </UserControl>
- using System;
-
- namespace Presentation.ViewModel
- {
-
-
-
- public class WelcomePageViewModel
- {
- #region Properties
-
-
-
- private string _imGoodByeText = "This is binded from WelcomePageViewModel, Thank you for being part of this Blog!";
-
-
-
- public string ImGoodByeText
- {
- get { return _imGoodByeText; }
- set { _imGoodByeText = value; }
- }
- #endregion
-
- }
- }
- And now open code behind WelcomePageView, so that we can set datacontext property from constructor.
- using Presentation.ViewModel;
- using System.Windows.Controls;
-
- namespace Presentation.View
- {
-
-
-
- public partial class WelcomePageView : UserControl
- {
- public WelcomePageView()
- {
- InitializeComponent();
- this.DataContext = new WelcomePageViewModel();
- }
- }
- }
- 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 :)