© 2009 RoCk SOLid KnOwledge 1
RoCkKnOwledge
SOLiD
http://www.rocksolidknowledge.com
Designing UIs with theComposite Application Guidance
David Wheeler
© 2009 RoCk SOLid KnOwledge 2
Agenda
Background to composite applications
Overview of Prism v2for WPF
Hopefully not too many slides
© 2009 RoCk SOLid KnOwledge 3
Composite applications
Enterprise applications can get messy - fastlong-lived, new pieces being added all the time
multiple development teams
varied sources of data
poor separation of concerns / close coupling
difficulties in testing
Challenges for enterprise application developers
© 2009 RoCk SOLid KnOwledge 4
Composite applicationsWhat is a composite application?
legacy
legacy
services
services
unified composite
© 2009 RoCk SOLid KnOwledge 5
Composite applicationsComposition is also present in the UI
UI built using composition
Loosely coupled communication required between componentse.g. “Save All” command
logger
Shared servicese.g. logging
© 2009 RoCk SOLid KnOwledge 6
Composite applications
Published by MS Patterns & Practices Group
Guidance on how to create composite appsreference application
“how to” and documentation
Composite Application Library (CAL)
WPF/Silverlight replacement for CABstill consider CAB for mixed-mode apps
See microsoft.com/compositeWPF
Prism v2
© 2009 RoCk SOLid KnOwledge 7
Prism v2
Utilises core features of WPFdata binding for view <-> viewmodel
ICommand implementation for commands
Lightweight inheritance footprintviews are just standard user controls
shell is just a normal WPF Window (typically)
Focus on WPF
© 2009 RoCk SOLid KnOwledge 8
Prism v2
Dependency Injection container
Bootstrapper
Shell
Modules
Views
Services
Core parts
© 2009 RoCk SOLid KnOwledge 9
Dependency Injection
DI (or IoC) used to create objectsregister types / instances with container
can be done using configuration or code
clients can query the container for objects
DI container can inject objects as neededlargely done using .ctor injection in Prism
Default container in Prism is Unityroll your own by implementing IUnityContainer
© 2009 RoCk SOLid KnOwledge 10
Dependency Injection
TypeAContainer
Register ()
Container
TypeB
Resolve<TypeB>() B
A
public class TypeB {public TypeB( TypeA a ){ ... }
}
© 2009 RoCk SOLid KnOwledge 11
Bootstrapper
Bootstrapper needed when DI is in usegets the application started
Prism provides a UnityBootstrapperprepares the default services used by Prism
e.g. logging, region management
Typically created in App’s OnStartup method
© 2009 RoCk SOLid KnOwledge 12
BootstrapperApplication start-up sequence
App
Bootstrapper
OnStartUp
Configure containerConfigure core servicesCreate shellConfigure region mappingsInitialise modules
Run
© 2009 RoCk SOLid KnOwledge 13
Shell
Shell provides the main window for the apptypically hosts one or more regions
ToolbarRegion
InfoRegion
Shell
MainRegion
© 2009 RoCk SOLid KnOwledge 14
Regions
Regions are named placeholdersviews are activated within a region
controlled using a RegionManager
Regions are set with an attached propertyRegionManager.RegionName
Regions can becontent controls (notionally a single active view)
items controls (such as TabControl)
© 2009 RoCk SOLid KnOwledge 15
Regions
<!-- Within the Shell.xaml file -->
<TabControlxmlns:cal= http://www.codeplex.com/CompositeWPFcal:RegionManager.RegionName=“MainRegion” />
...
<ContentControlxmlns:cal= http://www.codeplex.com/CompositeWPFcal:RegionManager.RegionName=“EditorRegion” />
...
© 2009 RoCk SOLid KnOwledge 16
Composite applications
Ideally break applications into modulese.g. HR module, payroll module, sales module
Module can contain multiple views / services
Modularity
HR
Common
Payroll Sales Logger
Modules
© 2009 RoCk SOLid KnOwledge 17
Modules
Modules implement the IModule interfacesingle Initialize() method akin to entry point
Typically creates the services / views it needs
Uses .ctor injection for two key itemsIUnityContainer for registering services
IRegionManager for working with regions
Stick to one module per assembly
© 2009 RoCk SOLid KnOwledge 18
Modules
public class HRModule : IModule{
IRegionManager regionManager;IUnityContainer unityContainer;public HRModule( IUnityContainer unityContainer,
IRegionManager regionManager ){
this.unityContainer = unityContainer;this.regionManager = regionManager;
}
public void Initialize(){
// register services// create views / view models
}}
© 2009 RoCk SOLid KnOwledge 19
Module loading
Modules are stored in a cataloguecreated by the Bootstrapper
Can locate modules a number of wayscode-driven catalog (easiest, least flexible)
XAML-driven
configuration-driven
directory-driven (ultimate in dynamism)
custom
© 2009 RoCk SOLid KnOwledge 20
Module loading
Modules can be loaded at startup
on demand
Modules can depend upon other modulesensures loading in the correct sequence
© 2009 RoCk SOLid KnOwledge 21
Module catalogues
public class Bootstrapper : UnityBootstrapper{
protected override IModuleCatalog GetModuleCatalog(){
ModuleCatalog catalog = new ModuleCatalog();catalog.AddModule( typeof( MessagingModule ) );catalog.AddModule( typeof( HRModule ) );catalog.AddModule( typeof( PayrollModule ), “HRModule” );return catalog;
}
protected override DependencyObject CreateShell(){
...}
}
© 2009 RoCk SOLid KnOwledge 22
Views
Views are placed in regionscomposite views themselves define more regions
Represent a portion of the UI for a module
Typically created through two approaches“View first” - views created by module
“Presenter first” - views injected into view model
© 2009 RoCk SOLid KnOwledge 23
Views
More often than not, a simple UserControlcan be a template, custom control, etc.
key is that there is no inheritance constraint
Organise your project to support viewsplace them in a Views folder in your module
Use binding to populate their dataalso use binding to set commands
© 2009 RoCk SOLid KnOwledge 24
View <-> Model <-> ViewModel
Prism tends to use V-M-VM pattern
View
ViewModel
Model
Data-bound UI
Data-bound propertiesCommands
Service callsData access
© 2009 RoCk SOLid KnOwledge 25
Creating views
public class HRModule : IModule{
IRegionManager regionManager;...// regionManager injected using DI container
public void Initialize(){
HRMainView view = new HRMainView();IRegion region = regionManager.Regions[“MainRegion”];region.Add( view );region.Activate( view );
}}
© 2009 RoCk SOLid KnOwledge 26
Services
Services != Web Services(well, not ALL the time, anyway)
Module registers service with DI containerconsumers can then resolve service as needed
Some services are common across modulescreate in an infrastructure module
© 2009 RoCk SOLid KnOwledge 27
Services
Prism provides a default logging mechanismvia the ILoggerFacade interface
can use any logging architecturee.g. log4net, Ent Lib logging block, etc.
Logging service
© 2009 RoCk SOLid KnOwledge 28
Consuming services
public class HRModule : IModule{
IUnityContainer unityContainer;...// unityContainer injected using DI container
public void Initialize(){
...ILoggerFacade logger = unityContainer.Resolve<ILoggerFacade>();logger.Log("Hey, I've been logged", Category.Info, Priority.Low);
}}
© 2009 RoCk SOLid KnOwledge 29
Commands
WPF has a strong command mechanismrouted commands and ICommand
A couple of important limitationsfocus (logical) and otherwise is problematic
command bindings often have to be set at root
doesn’t do “Save All” functionality well
Background
© 2009 RoCk SOLid KnOwledge 30
Commands
Invoker ICommand
RealCommand
Receiver
© 2009 RoCk SOLid KnOwledge 31
Commands
Prism provides custom command typesDelegateCommand
CompositeCommand
Commands typically bound to view controlscommands are exposed by ViewModel
Prism commands
© 2009 RoCk SOLid KnOwledge 32
CommandsA simple DelegateCommand
public class HRViewModel{
public DelegateCommand<string> Search { get; private set; }
public HRViewModel(){
Search = new DelegateCommand<string>( OnSearch, OnCanSearch );}
void OnSearch( string employeeName ) { ... }
bool OnCanSearch( string employeeName ) { ... }}
<Button Command=“{Binding Path=Search}”CommandParameter=“{Binding Path=EmployeeName, Mode=TwoWay}”Content=“Search” />
© 2009 RoCk SOLid KnOwledge 33
CommandsCompositeCommand
“Save All”
“Save” “Save” “Save”
© 2009 RoCk SOLid KnOwledge 34
CommandsA simple CompositeCommand
public class HRViewModel{
public DelegateCommand<string> Save { get; private set; }
public HRViewModel(){
Save = new DelegateCommand<string>( OnSave, OnCanSave );GlobalCommands.SaveAllCommand.RegisterCommand( Save );
}...
}
public static class GlobalCommands{
public static CompositeCommand SaveAllCommand = new CompositeCommand();
}
© 2009 RoCk SOLid KnOwledge 35
Commands
Code on previous slide a bit “icky”hard dependency on the GlobalCommands class
Prefer to proxy the global commandregister a service with the DI container
enables the command to be mocked out
Proxying composite commands
© 2009 RoCk SOLid KnOwledge 36
Events
Routed events not reliable for compositesonly bubble up the visual tree
Modules need a way to communicatecommands are “do it now”
events are “hey, you might be interested”
CAL contains a pub/sub event aggregator
© 2009 RoCk SOLid KnOwledge 37
EventsModularity
Sales Finance
Event
Publisher Subscriber
© 2009 RoCk SOLid KnOwledge 38
EventsA simple event
EventAggregator agg = unityContainer.Resolve<EventAggregator>();OrderPlacedEvent evt = agg.GetEvent<OrderPlacedEvent>();evt.Publish( new OrderInfo() { ... } );
public class OrderPlacedEvent : CompositePresentationEvent<OrderInfo>{}
public class OrderInfo{ ... }
EventAggregator agg = unityContainer.Resolve<EventAggregator>();OrderPlacedEvent evt = agg.GetEvent<OrderPlacedEvent>();evt.Subscribe( o => DataContext = o, ThreadOption.UIThread, false );
© 2009 RoCk SOLid KnOwledge 39
Summary
Learning curve relatively shallow
However...you need to buy into DI
you need to be comfortable with binding in WPF
discipline is key to success
might still need CAB for mixed WPF/WinForms
© 2009 RoCk SOLid KnOwledge 40
Summary
Prism v2 offers solid guidanceaddresses common architectural challenges
supports WPF and Silverlight
extensible
minimal inheritance enforcement
commands and events good in themselves
Get the bitshttp://microsoft.com/compositeWPF
© 2009 RoCk SOLid KnOwledge 41
RoCkKnOwledge
SOLiD
http://www.rocksolidknowledge.com
Q & AThanks for coming