Prism 6 from ground up by 10 minutes

3 בApril 2016

In this post we will build a small app using Prism 6 and Unity together with all necessary  tools.
One of the commonly known issues  with Prism is the different between versions and dlls.
So I choose in the demo to use the last nugget package and to trust it.
Than to manipulate all around it,
Well surprising way, installing unity for Prism 6 was include automatically all Prism 6 dependencies which reduce any computability  issues
Well, Prism architecture is simple,
A.

We have Shell which is the main window and probably the only window in the application.

B.

We have Regions inside the Shel and they would be kind of Xaml Content control.

C.

We have a Container meaning IOC Container to resolve dependencies services and for initiate the viewModels  attached to views.

D.

We have Modules m while module meaning a stand alone component and most likely a separate dll, every Module has is own views, viewModels, services,  controllers etc. and can act as application without dependencies with outside modules.

E.

We have module-catalog  who organize those modules.

F.

We have a Bootstrapper which is the kickstart of he application.

G.

We have RegionManager who controles the regions and can inject any module the specific region.

H.

We have the Event aggregator to contact between modules.

****************************************************************************************

Now lets build a small demo from scratch..
Open new Project and  use nugget package for

image

These will bring us the latest prism + latest unity for prism, since older versions are deprecated and manually install might broke the design.
Now for the real action:
1.    Create the shell (nothing but a simple WPF window)
2.    Remove the startup uri from app xaml file.
3.    Create/Config a unity Bootstrapper:
There are several things we mus do in the bootstrapper that Prism force us override although with havnt any real implementation.

The simple Bootstrapper will be :

class Bootstrapper : UnityBootstrapper

    {

        protected override DependencyObject CreateShell()

        {

            return this.Container.Resolve<MainWindow>();

        }


        protected override void InitializeShell()

        {

            base.InitializeShell();

            App.Current.MainWindow = (Window)this.Shell;

            App.Current.MainWindow.Show();

        }


        protected override void ConfigureModuleCatalog()

        {

            base.ConfigureModuleCatalog();

            ModuleCatalog moduleCatalog = (ModuleCatalog)this.ModuleCatalog;


           // moduleCatalog.AddModule(x);

           // moduleCatalog.AddModule(y);

           // moduleCatalog.AddModule(z);

        }

        protected override void ConfigureContainer()

         {

           // Container.RegisterInstance<>();

            base.ConfigureContainer();

         }

    }

4.    In the Xaml Shell you need the following namespace for register regions

xmlns:prism=http://prismlibrary.com/

the xaml of the Shell should be something basic like:

 

<Grid>

   <Grid.RowDefinitions>

       <RowDefinition Height="*"/>

       <RowDefinition Height="*"/>

   </Grid.RowDefinitions>


   <ContentControl prism:RegionManager.RegionName="RegionA" Grid.Row="0"/>

   <ContentControl prism:RegionManager.RegionName="RegionB" Grid.Row="1"/>


d>


 

5.    Modules.
Add two new dll’s, those dll’s  will present and promote  the Module concept of Prism.
The library output of them should be of UI type, so recommended to add new WPF projects than reset the lib type for Class Library and delete the App class, main window, and app.Config since you don’t need them,

 

image

Another option is to use regular dll than add reference to
PresentationCore, PresentationFramework, System.Xaml, and WindowsBase dll’s.

Any module should provide its own Views/viewModeids and non global dependencies,
And having a separate assembly, meaning install the Unity for Prism 6 nugget per each module.
Now, the most important action you need is define the module implementation:

//[ModuleDependency(moduleName ...)]

    public class CustomerModule : IModule

    {

        private IRegionManager _regionManager;


        public void Initialize()

        {

         _regionManager.RegisterViewWithRegion("UpperRegion",

          typeof(CustomersView));

        }


        public CustomerModule(IRegionManager regionManager)

        {

            _regionManager = regionManager;

        }

    }

 

The Initialize function is auto called while register this assembly as Prism Module.

A structure of a module should be something like :

image

6.    Services and Contracts. Considered regular application with any global services and some application types, so create any appropriate assembly, and set your services/contracts
For example a commonly trick for distributed application is constants for public naming like:
namespace Contracts

namespace Contracts

     {

       public  class ApplicationNames

       {

          public const string UpperRegion = "UpperRegion";

          public const string MainRegion = "MainRegion";

          public const string ProductModule = "ProductModule";

          public const string CustomerModule = "CustomerModule";

       }

  }

But, for real services like this one:

namespace Contracts

{

    public interface ITimeService

    {

        DateTime GetTime();

    }


    public class TimeService : ITimeService

    {

        public DateTime GetTime()

        {

            return DateTime.Now;

        }

    }

}

7.    Go back to your Bootstrapper and reedit  the ConfigureModuleCatalog function by Register those real Modules after create them. And also any relevant services.
Like:

protected override void ConfigureModuleCatalog()

{

uleCatalog.AddModule(typeof(CustomerModule.CustomerModule));


protected override void ConfigureContainer()

{

       Container.RegisterInstance<ITimeService>(new TimeService());


8.    You very close to end..
Lets review and summary the temporary work.
We create a Shell window,
We create a Bootstrapper that  showing the shell (CreateShell , InitializeShell),
Register the Modules to the Module-catalog(ConfigureModuleCatalog),
and register the services to Unity-Container(ConfigureContainer),

9.    View + ViewModels,
Views are simple, the only interesting part is while setting DataContext,

xmlns:prism="http://prismlibrary.com/"

iewModelLocator.AutoWireViewModel="True"

by convention if the name of the ViewModel is same as view
(TopicsView = TopicsViewModel) its will automatically attached

ViewModels:
Every ViewModel must inherits from BindableBase class:

public class CustomersViewModel : BindableBase

it allow us thing like:

public string HelloText

        {

            get { return helloText; }

            set

            {

                helloText = value;

                OnPropertyChanged(() => HelloText);

            }

        }

Now, its very likely to has some Prism/Unity requests in the ViewModel, so we must ask for relevant types in the viewModel constructor like:

public IUnityContainer _contianer { get; set; }

      public IEventAggregator _eventAggregator { get; set; }

      public CustomersViewModel(IEventAggregator eventaggregator ,

                                                     IUnityContainer  contianer)

        {

            _eventAggregator = eventaggregator;

            _contianer = contianer;

             ITimeService timeService = _contianer.Resolve<ITimeService>();

            var timetest = timeService.GetTime();

                }

Since Prism activate this class it will be Prism responsibility to provide those parameters, and we explain the EventAggregator right away.

10.    EventAggregator –  a major part of Prism, when try to send/receive messages between Moduls,

a.    Define a Message:
Every Event must be of Generic type of PubSubEvent like:

public class ParamsBase : Prism.Events.PubSubEvent<ParamsBase>

    {

        public string Value { get; set; }


        public ParamsBase()

        {


        }

    }

If it cross module Event you probably define it in Contracts assembly..

Create/Send Message:

PubSubEvent<ParamsBase> vv = _eventAggregator.GetEvent<ParamsBase>()

vv.Publish(new ParamsBase() { Value = "Hello" });


Receive a Message:

Class ProductsViewModel

{

  private string helloText;


   public ProductsViewModel(IEventAggregator eventaggregator)

 {

     _eventAggregator = eventaggregator;

     PubSubEvent<ParamsBase> vv =  _eventAggregator.GetEvent<ParamsBase>();

         vv.Subscribe(onEvent, false);

  }

        private void onEvent(ParamsBase param)

        {

            HelloText = param.Value;

        }

               }

 

הוסף תגובה
facebook linkedin twitter email

Leave a Reply

Your email address will not be published. Required fields are marked *

2 תגובות

  1. jhon ming15 בMay 2016 ב 13:53

    Very helpful, thank you

    Reply
  2. MS18 בJuly 2016 ב 18:43

    Is it possible to use Prism 6 with SimpleInjector instead of Unity?

    Reply