Starting a modular application development using Prism,
WPF and Unity container.
Step 1
·
In Visual Studio 2010, start a new WPF project.
·
Remove MainWindow.xaml file that was
automatically created.
· Remove StartupUri="MainWindow.xaml" from App.xaml file.
· Add the following references
· Remove StartupUri="MainWindow.xaml" from App.xaml file.
· Add the following references
o
Microsoft.Practices.Prism
o Microsoft.Practices.Prism.Unity
o Microsoft.Practices.Prism.UnityExtensions
o Microsoft.Practices.Prism.ServiceLocation
o Microsoft.Practices.Prism.Interactivity
·
Create a class called Bootstrapper.cs and derive
this from UnityBootstrapper class.
·
Create
the main shell window by adding a new wpf window called PrismAppShell.xaml
·
Implement the abstract method CreateShell in
Bootstrapper class.
·
Override two methods in Bootstrapper class
o
InitializeModules
o
ConfigureModuleCatalog
·
Inside App.xaml.cs within OnStartup method instantiate Bootstratper object and call its Run()
Inside App.xaml.cs within OnStartup method instantiate Bootstratper object and call its Run()
Therefore the files are
going to look like this
App.xaml
<Application x:Class="Prism.ModuleExmaple.App"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
>
<Application.Resources>
</Application.Resources>
</Application>
App.xaml.cs
public partial class App : Application
{
protected
override void
OnStartup(StartupEventArgs e)
{
base.OnStartup(e);
BootStrapper
bootstrapper = new BootStrapper();
bootstrapper.Run();
}
}
Bootstrapper.cs
protected
override System.Windows.DependencyObject CreateShell()
{
return
this.Container.Resolve<PrismAppShell>();
}
protected
override void
InitializeModules()
{
base.InitializeModules();
App.Current.MainWindow
= (PrismAppShell)this.Shell;
App.Current.MainWindow.Show();
}
protected
override void
ConfigureModuleCatalog()
{
base.ConfigureModuleCatalog();
this.ModuleCatalog.AddModule(null); // TODO -
placeholder
}
}
PrismAppShell.xaml
<Window x:Class="Prism.ModuleExmaple.PrismAppShell"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="PrismAppShell" Height="300" Width="300">
<Grid>
</Grid>
</Window>
Now one with run this application from visual studio the
empty shell window will come up like below.
Step 2
Now let us divide the main shell xaml into regions and mark them with regional names.
Step 3
In step 3. let us create few individual modules such and load them on the regions on the shell as we defined before. Also in the shell xaml on the top we used a ribbon control and defined the RibbonRegion there, a TreeView control on the left for TreeRegion, a TabControl in the middle for BlotterRegion. Bottom and right (StatusRegion and AlertRegion) we kept as ContentControl still.
Step 2
Now let us divide the main shell xaml into regions and mark them with regional names.
<Window x:Class="Prism.ModuleExmaple.PrismAppShell"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:prism="http://www.codeplex.com/prism"
Title="PrismAppShell" Height="900" Width="1200">
<Grid x:Name="LayoutRoot">
<DockPanel LastChildFill="True" HorizontalAlignment="Stretch" Name="dockPanel1" VerticalAlignment="Stretch">
<StackPanel Orientation="Horizontal" DockPanel.Dock="Top" Background="#FFCCD4F8" Height="100">
<ContentControl prism:RegionManager.RegionName="RibbonRegion"></ContentControl>
</StackPanel>
<StackPanel Orientation="Horizontal" DockPanel.Dock="Bottom" Background="#FFD9E1EF" Height="100">
<ContentControl prism:RegionManager.RegionName="StatusRegion"></ContentControl>
</StackPanel>
<ScrollViewer>
<StackPanel Orientation="Vertical" DockPanel.Dock="Left" Background="#FF50576F" Width="200">
<ContentControl prism:RegionManager.RegionName="TreeRegion"></ContentControl>
</StackPanel>
</ScrollViewer>
<StackPanel Orientation="Vertical" DockPanel.Dock="Right" Background="#FF677BA7" Width="100">
<ContentControl prism:RegionManager.RegionName="AlertRegion"></ContentControl>
</StackPanel>
<ScrollViewer HorizontalAlignment="Stretch" VerticalAlignment="Stretch">
<StackPanel HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Background="#FFC0DBF2">
<ContentControl prism:RegionManager.RegionName="BlotterRegion" HorizontalAlignment="Stretch" VerticalAlignment="Stretch"></ContentControl>
</StackPanel>
</ScrollViewer>
</DockPanel>
</Grid>
</Window>
Step 3
In step 3. let us create few individual modules such and load them on the regions on the shell as we defined before. Also in the shell xaml on the top we used a ribbon control and defined the RibbonRegion there, a TreeView control on the left for TreeRegion, a TabControl in the middle for BlotterRegion. Bottom and right (StatusRegion and AlertRegion) we kept as ContentControl still.
<Window x:Class="PrismApp.Shell.PrismAppShell"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:prism="http://www.codeplex.com/prism"
Title="PrismAppShell" Height="900" Width="1200"
xmlns:my="http://schemas.microsoft.com/winfx/2006/xaml/presentation/ribbon"
>
<Window.Resources>
<DataTemplate x:Key="crap">
<StackPanel Width="100" Height="18"></StackPanel>
</DataTemplate>
<Style x:Key="TabItemStyleKey" TargetType="{x:Type TabItem}">
<Setter Property="Header" Value="{Binding Path=DataContext.ViewTile}"></Setter>
<Setter Property="HeaderTemplate" Value="{Binding Source={StaticResource crap}}"></Setter>
</Style>
<Style x:Key="TreeItemStyleKey" TargetType="{x:Type TreeViewItem}">
<Setter Property="Height" Value="Auto"></Setter>
<Setter Property="HorizontalAlignment" Value="Left"/>
<Setter Property="VerticalAlignment" Value="Top" />
<Setter Property="BorderThickness" Value="0" />
</Style>
</Window.Resources>
<Grid x:Name="LayoutRoot">
<DockPanel LastChildFill="True" HorizontalAlignment="Stretch" Name="dockPanel1"
VerticalAlignment="Stretch">
<my:Ribbon prism:RegionManager.RegionName="RibbonRegion" DockPanel.Dock="Top"
HorizontalAlignment="Stretch"
VerticalAlignment="Stretch" Name="ribbon1" Height="150"/>
<StackPanel Orientation="Horizontal" DockPanel.Dock="Bottom" Background="#FFD9E1EF" Height="100">
<ContentControl prism:RegionManager.RegionName="StatusRegion"></ContentControl>
</StackPanel>
<ScrollViewer>
<StackPanel Orientation="Vertical" DockPanel.Dock="Left" MinWidth="150" MaxWidth="200">
<TreeView ItemContainerStyle="{StaticResource TreeItemStyleKey}"
prism:RegionManager.RegionName="TreeRegion"
Name="treeView1"
HorizontalAlignment="Stretch"
VerticalAlignment="Stretch"
BorderThickness="0"
/>
</StackPanel>
</ScrollViewer>
<StackPanel Orientation="Vertical" DockPanel.Dock="Right" Background="#FF677BA7" Width="100">
<ContentControl prism:RegionManager.RegionName="AlertRegion"></ContentControl>
</StackPanel>
<ScrollViewer HorizontalAlignment="Stretch" VerticalAlignment="Stretch">
<StackPanel HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Background="#FFC0DBF2">
<TabControl ItemContainerStyle="{StaticResource TabItemStyleKey}"
prism:RegionManager.RegionName="BlotterRegion"
Name="tabControl1"
HorizontalAlignment="Stretch"
VerticalAlignment="Stretch" Width="Auto">
</TabControl>
</StackPanel>
</ScrollViewer>
</DockPanel>
</Grid>
</Window>
Cash blotter module registers view like this.
public class CashBlotterModule
: IModule
{
private
readonly IRegionViewRegistry
regionViewRegistry = null;
public
CashBlotterModule(IRegionViewRegistry
regionViewRegistry)
{
this.regionViewRegistry
= regionViewRegistry;
}
public void Initialize()
{
this.regionViewRegistry.RegisterViewWithRegion("BlotterRegion", typeof(CashBlotterView));
this.regionViewRegistry.RegisterViewWithRegion("TreeRegion", typeof(CashItemsTreeView));
}
}
And bootstrapper loads module like this. (IN next section
this will be worked on further to load using container and decouple.
public class BootStrapper
: UnityBootstrapper
{
protected
override System.Windows.DependencyObject CreateShell()
{
return
this.Container.Resolve<PrismAppShell>();
}
protected
override void
InitializeModules()
{
base.InitializeModules();
App.Current.MainWindow
= (PrismAppShell)this.Shell;
App.Current.MainWindow.Show();
}
protected
override void
ConfigureModuleCatalog()
{
base.ConfigureModuleCatalog();
ModuleCatalog
moduleCatalog = (ModuleCatalog)this.ModuleCatalog;
moduleCatalog.AddModule(typeof(PrismApp.Module.Cash.Blotter.CashBlotterModule)); //
Seems like as soon as you add a new module, internally seletor module adopter
(since blotter region is on tab control), automatically adds a tab item)
moduleCatalog.AddModule(typeof(PrismApp.Module.Deriv.Blotter.DerivBlotterModule));
//moduleCatalog.AddModule("CashBlotterModule",
"PrismApp.Module.Cash.Blotter.CashBlotterModule");
}
}
In above code, inside ConfigureModuleCatalog the module
loading will be upgraded in the following section.
When we run now, the skeleton application comes up like this
Step 4
In step 4, we have
After all the above steps in step 4, our skeleton app looks like the following.
When we run now, the skeleton application comes up like this
Step 4
In step 4, we have
- Replaced the wpf datagrid with devexpress grid control, wpf toolbox ribbon with devexpress ribbon control.
- View Injection - done view injection from cash blotter module and ticket module and as well from derivatives blotter and ticket module.
- Injected views in desired prism regions on the shell, i.e. on BlotterRegion, RibbonRegion, TreeRegions.
- Model - connected to database for fake trade data.
- ViewModel - created a number of view model classes in order for the views to bind to trades data.
After all the above steps in step 4, our skeleton app looks like the following.