In
Prism we have 2 different dependency Injection Containers: Unity and MEF
Here
I ll demonstrate Unity approach for creating the Modular Silverlight
Application.
Let’s
say we have the following modules –
Header
Module – HMModule
Left Module – LMModule
Center
Module – CMModule
OnDemand
Module – DMModule
So
the look will be something like below -
Here
I am trying to achive the following –
1. The
first 3 module should be downloaded and Initialized on Application Start.
2. The
respective View should be registed to the specific Region of the Shell.
3. Click
on a View of the Hearder to be Handled by the Center Module – Ex of Event
Aggregator
4. Click
on the Button in Center Module should dynamicy Load the Module and the specific
View should be displayed in the RadWindow.
5. How
to use ServiceLocator to get the instance of Prism interfaces.
Code - Shell.xaml
<UserControl x:Class="PrismStart.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:R="http://www.codeplex.com/prism"
mc:Ignorable="d"
d:DesignHeight="600" d:DesignWidth="900">
<Canvas>
<ItemsControl Canvas.Left="0" Canvas.Top="0" x:Name="HMRegion" R:RegionManager.RegionName ="HMRegion" Height="85" Width="888" />
<ItemsControl Canvas.Left="0" Canvas.Top="90" x:Name="LMRegion" R:RegionManager.RegionName ="LMRegion" Height="468" Width="100"/>
<ItemsControl Canvas.Left="110" Canvas.Top="90" x:Name="CMRegion" R:RegionManager.RegionName ="CMRegion" Height="468" Width="778"/>
</Canvas>
</UserControl>
I am creating
3 region in the Shell as highlighted above
Code - Bootstrpper.cs
using System.Windows;
using Microsoft.Practices.Prism.UnityExtensions;
using Microsoft.Practices.Prism.Modularity;
namespace PrismStart
{
public class Bootstraper
: UnityBootstrapper
{
protected
override DependencyObject
CreateShell()
{
Shell
shell = new Shell();
Application.Current.RootVisual
= shell;
return
shell;
}
protected
override IModuleCatalog
CreateModuleCatalog()
{
ModuleCatalog
mc = new ModuleCatalog();
ModuleInfo
mi1 = new ModuleInfo()
{
ModuleName = "Header",
InitializationMode = InitializationMode.WhenAvailable,
ModuleType = "HMModule.HM, HMModule, Version=1.0.0.0,
Culture=neutral, PublicKeyToken=null",
Ref = "HMModule.xap"
};
ModuleInfo
mi2 = new ModuleInfo()
{
ModuleName = "Centre",
InitializationMode = InitializationMode.WhenAvailable,
ModuleType = "CMModule.CM, CMModule, Version=1.0.0.0,
Culture=neutral, PublicKeyToken=null",
Ref = "CMModule.xap"
};
ModuleInfo
mi3 = new ModuleInfo()
{
ModuleName = "Left",
InitializationMode = InitializationMode.WhenAvailable,
ModuleType = "LMModule.LM, LMModule, Version=1.0.0.0,
Culture=neutral, PublicKeyToken=null",
Ref = "LMModule.xap"
};
ModuleInfo
mi4 = new ModuleInfo()
{
ModuleName = "OnDemand",
InitializationMode = InitializationMode.OnDemand,
ModuleType = "OnDemandModule.OM, OnDemandModule, Version=1.0.0.0,
Culture=neutral, PublicKeyToken=null",
Ref = "OnDemandModule.xap"
};
mc.AddModule(mi1);
mc.AddModule(mi2); mc.AddModule(mi3); mc.AddModule(mi4);
return
mc;
}
}
}
Here
you can notice how are creating Module Catalog with the InitializationMode to
be either WhenAvailable or OnDemand. The same can be achieved using the ModuleCatalog.xaml
file. The content of the same will be similar to this.
ModuleCatalog.xaml
<prism:ModuleCatalog xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:sys="clr-namespace:System;assembly=mscorlib"
xmlns:prism="clr-namespace:Microsoft.Practices.Prism.Modularity;assembly=Microsoft.Practices.Prism">
<prism:ModuleInfo Ref="HMModule.xap" ModuleName="Header" ModuleType="HMModule.HM, HMModule, Version=1.0.0.0, Culture=neutral,
PublicKeyToken=null" InitializationMode="WhenAvailable"/>
<prism:ModuleInfo Ref="CMModule.xap" ModuleName="Centre" ModuleType="CMModule.CM, CMModule, Version=1.0.0.0, Culture=neutral,
PublicKeyToken=null" InitializationMode="WhenAvailable"/>
<prism:ModuleInfo Ref="LMModule.xap" ModuleName="Left" ModuleType="LMModule.LM, LMModule, Version=1.0.0.0, Culture=neutral,
PublicKeyToken=null" InitializationMode="WhenAvailable"/>
<prism:ModuleInfo Ref="Sunix.Acc.App.xap" ModuleName="Accounting" ModuleType="Sunix.Acc.App.AccModule, Sunix.Acc.App, Version=1.0.0.0,
Culture=neutral, PublicKeyToken=null" InitializationMode="OnDemand"/>
</prism:ModuleCatalog>
Next
you need to modify the CreateModuleCatalog method as below –
protected override IModuleCatalog CreateModuleCatalog()
{
ModuleCatalog moduleCatalog =
Microsoft.Practices.Prism.Modularity.ModuleCatalog.CreateFromXaml(new Uri("ModuleCatalog.xaml", UriKind.Relative));
return
moduleCatalog;
}
Code – Header Module (HM.cs)
using Microsoft.Practices.Prism.Modularity;
using Microsoft.Practices.Prism.Regions;
namespace HMModule
{
public class HM : IModule
{
IRegionManager
rm;
public
HM(IRegionManager _rm)
{
rm = _rm;
}
public void Initialize()
{
rm.RegisterViewWithRegion("HMRegion",
typeof(HMView));
}
}
}
Here
you can see how I am registering a View to the Prism Region.
Code – HMView (xaml and cs)
<UserControl x:Class="HMModule.HMView"
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"
mc:Ignorable="d"
d:DesignHeight="100" d:DesignWidth="800">
<Grid x:Name="LayoutRoot" Background="#FF2B2525">
<StackPanel Orientation="Vertical">
<TextBlock Text="Header Module" Foreground="#FFDEC2C2" Height="50" FontSize="14" FontWeight="Bold" HorizontalAlignment="Center" VerticalAlignment="Center" />
<StackPanel Orientation="Horizontal">
<Button Command="{Binding
headerClicked,Mode=TwoWay}" CommandParameter="{Binding ElementName=textBox1,Path=Text,Mode=TwoWay}" Content="Publish Event - To be
Handled by Center Module" Height="23" Name="button1" VerticalAlignment="Top" />
<TextBlock Text=" Parameter Value to be
Passed :" Foreground="#FFE2CDCD" />
<TextBox Height="23" HorizontalAlignment="Left" Name="textBox1" VerticalAlignment="Top" Width="150" />
</StackPanel>
</StackPanel>
</Grid>
</UserControl>
using System.Windows.Controls;
namespace HMModule
{
public partial class HMView : UserControl
{
public
HMView(HMViewModel hMViewModel)
{
InitializeComponent();
this.Loaded
+= (s, e) => { this.DataContext =
hMViewModel; };
}
}
}
Code – HMViewModel.cs
using System.Windows.Input;
using Microsoft.Practices.Prism.Events;
using SahreCode;
using SharedCode;
namespace HMModule
{
public class HMViewModel
{
IEventAggregator
aggregator { get; set;
}
public ICommand headerClicked { get;
set; }
public
HMViewModel(IEventAggregator _aggregator)
{
headerClicked = new DC(executeCentre);
aggregator = _aggregator;
}
public void executeCentre(object
param)
{
aggregator.GetEvent<HeaderViewEvent>().Publish(param.ToString());
}
}
}
Code – Center Module (CM.cs)
using Microsoft.Practices.Prism.Modularity;
using Microsoft.Practices.Prism.Regions;
namespace CMModule
{
public class CM : IModule
{
IRegionManager
rm;
IModuleManager
mm;
public
CM(IRegionManager _rm, IModuleManager _mm)
{
rm = _rm;
mm = _mm;
}
public void Initialize()
{
rm.RegisterViewWithRegion("CMRegion", typeof(CMView));
}
}
}
Code – CMView (xaml and cs)
<UserControl x:Class="CMModule.CMView"
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"
mc:Ignorable="d"
Height="600" Width="800">
<Grid x:Name="LayoutRoot" Background="#FFC7C2C2">
<Grid.RowDefinitions>
<RowDefinition Height="42*" />
<RowDefinition Height="55*" />
<RowDefinition Height="503*" />
</Grid.RowDefinitions>
<TextBlock Text="Center Module" FontSize="15" FontWeight="Bold" Foreground="Black" Grid.RowSpan="2" />
<TextBlock Grid.Row="1" Text="This module View is
subscribing to the Event Raised/Published by the Header Module View" FontSize="11" FontWeight="Bold" Foreground="Black" Grid.RowSpan="2" />
<Button Grid.Row="2" Content="Open View from
OnDemandLoad" Height="23" HorizontalAlignment="Left" Name="Demand" VerticalAlignment="Top" Width="221" Command="{Binding DemandCommand,Mode=TwoWay}" />
</Grid>
</UserControl>
using System.Windows;
using System.Windows.Controls;
using Microsoft.Practices.Prism.Modularity;
using Microsoft.Practices.Unity;
namespace CMModule
{
public partial class CMView : UserControl
{
private
CMViewModel cMViewModel;
private
IModuleManager mm;
private
IUnityContainer container;
public
CMView(CMViewModel cMViewModel, IModuleManager _mm, IUnityContainer
_container)
{
InitializeComponent();
mm = _mm;
container = _container;
this.cMViewModel
= cMViewModel;
this.Loaded
+= new RoutedEventHandler(CMView_Loaded);
}
void
CMView_Loaded(object sender, RoutedEventArgs e)
{
this.DataContext
= cMViewModel;
}
}
}
Code – CMViewModel.cs
using System;
using System.Windows.Input;
using SharedCode;
using Microsoft.Practices.Prism.Events;
using SahreCode;
using Microsoft.Practices.Prism.Modularity;
using Microsoft.Practices.Unity;
using Telerik.Windows.Controls;
using System.Linq;
using System.Collections.Generic;
namespace CMModule
{
public class CMViewModel
{
private
IEventAggregator aggregator;
private
IModuleManager mm;
private
IUnityContainer container;
public int MyProperty { get;
set; }
public ICommand DemandCommand { get;
set; }
private
List<string>
DownloadedModuleList;
private
string CurrentModuleName;
public
CMViewModel(IEventAggregator _aggregator, IModuleManager _mm, IUnityContainer
_container)
{
aggregator = _aggregator;
mm = _mm;
container = _container;
DemandCommand = new DC(OnDemand);
aggregator.GetEvent<HeaderViewEvent>().Subscribe(CentreHandler);
DownloadedModuleList = new List<string>();
}
private
void OnDemand(object
param)
{
CurrentModuleName = "OnDemand";
if
(!DownloadedModuleList.Contains(CurrentModuleName))
{
DownloadedModuleList.Add(CurrentModuleName);
mm.LoadModuleCompleted += new
EventHandler<LoadModuleCompletedEventArgs>(mm_LoadModuleCompleted);
mm.LoadModule(CurrentModuleName);
}
else
ShowView();
}
void
mm_LoadModuleCompleted(object sender, LoadModuleCompletedEventArgs e)
{
ShowView();
}
private
void ShowView()
{
Type x = container.Registrations.Where(o => o.Name
== "OMView").Select(y =>
y.RegisteredType).FirstOrDefault();
var
g = container.Resolve(x, "OMView");
RadWindow
win = new RadWindow();
win.Content = g;
win.Show();
}
public void CentreHandler(string
mess)
{
System.Windows.MessageBox.Show("Parameter
Passed: " + mess);
}
}
}
Above
highlighted piece of code is demonstarting how the OnDemand Module load is
working.
Code – OnDemand Module (OM.cs)
using Microsoft.Practices.Unity;
using Microsoft.Practices.Prism.Modularity;
namespace OnDemandModule
{
public class OM
: IModule
{
private
IUnityContainer container;
public OM(IUnityContainer
_container)
{
container = _container
container.RegisterType(typeof(OMView), "OMView", new
TransientLifetimeManager(), new Microsoft.Practices.Unity.InjectionConstructor("DHANANJAY"));
}
public void Initialize()
{
}
}
}
<UserControl x:Class="OnDemandModule.OMView"
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"
mc:Ignorable="d"
d:DesignHeight="300" d:DesignWidth="400">
<Grid x:Name="LayoutRoot" Background="White">
<StackPanel Orientation="Vertical">
<TextBlock Text="I am On Demand
View"/>
<TextBlock Text="{Binding PatientName}"/>
<Button Content="Change Patient" Command="{Binding
ChangePatient}"/>
</StackPanel>
</Grid>
</UserControl>
using System.Windows.Controls;
namespace OnDemandModule
{
public partial class OMView : UserControl
{
public
OMView(string ctr)
{
InitializeComponent();
this.DataContext
= new OMViewModel();
}
}
}
using System.Windows.Input;
using SahreCode;
using Microsoft.Practices.Unity;
namespace OnDemandModule
{
public class OMViewModel
: ViewModelBase
{
private
string patientName;
private
IUnityContainer _container;
public string PatientName
{
get
{ return patientName; }
set
{ patientName = value; firePC("PatientName"); }
}
public ICommand ChangePatient { get;
set; }
public
OMViewModel()
{
ChangePatient = new DC(OnChangePatient);
PatientName = "Dhananjay";
IUnityContainer container =
Microsoft.Practices.ServiceLocation.ServiceLocator.Current.GetInstance<IUnityContainer>();
}
public void InitializeVM(IUnityContainer
container)
{
_container = container;
}
private
void OnChangePatient(object
p)
{
PatientName = "Manav";
}
}
}
private void
Application_Startup(object sender, StartupEventArgs e)
{
Bootstraper
bs = new Bootstraper();
bs.Run();
}
Here
you can how easily we can make use of ServiceLocator to get the Instances of the Prism core
Interfaces.