One of the challenges I have found when using MVVM in Prism, is that out of the box it only supports the click event. Luckily there is an extensibility point here using the CommandBehaviourBase class which means we can tie command execution to any event the control can raise and then bind this using an attached property in the XAML.
There are 3 parts to the code – the example I am going to use is the SelectionChanged event of the ListBox control.
namespace PrismExtension.
CommandBehaviours
{
public class SelectedChangedBehaviour
: CommandBehaviorBase
<listbox
>
{
public SelectedChangedBehaviour
(ListBox element
) : base(element
)
{
element.
SelectionChanged += new SelectionChangedEventHandler
(element_SelectedChanged
);
}
private void element_SelectedChanged
(object sender, SelectionChangedEventArgs e
)
{
base.
ExecuteCommand();
}
}
}
This code is pretty simple in what it does. The constructor takes an instance of the control you want to attach the event handling code to. The event handling code then executes the command when the event you are watching for is fired. The next part is a bit more tricky.
In order to get this into the XAML as an attached property we need to create a static class.
namespace PrismExtension.
CommandBehaviours
{
public static class SelectedChanged
{
public static ICommand GetCommand
(DependencyObject obj
)
{
return (ICommand
)obj.
GetValue(CommandProperty
);
}
public static void SetCommand
(DependencyObject obj, ICommand value
)
{
obj.
SetValue(CommandProperty, value
);
}
public static readonly DependencyProperty CommandProperty
= DependencyProperty.
RegisterAttached("Command",
typeof(ICommand
),
typeof(SelectedChanged
),
new PropertyMetadata
(OnSetCommandCallback
));
public static readonly DependencyProperty CommandParameterProperty
= DependencyProperty.
RegisterAttached("CommandParameter",
typeof(object),
typeof(SelectedChanged
),
new PropertyMetadata
(OnSetCommandParameterCallback
));
private static void OnSetCommandCallback
(DependencyObject dependencyObject, DependencyPropertyChangedEventArgs e
)
{
ListBox element
= dependencyObject
as ListBox
;
if (element
!= null)
{
SelectedChangedBehaviour behavior
= GetOrCreateBehavior
(element
);
behavior.
Command = e.
NewValue as ICommand
;
}
}
public static void SetCommandParameter
(ListBox listbox,
object parameter
)
{
listbox.
SetValue(CommandParameterProperty, parameter
);
}
public static object GetCommandParameter
(ListBox listbox
)
{
return listbox.
GetValue(CommandParameterProperty
);
}
private static SelectedChangedBehaviour GetOrCreateBehavior
(ListBox element
)
{
SelectedChangedBehaviour behavior
= element.
GetValue(SelectedIndexChangedBehaviourProperty
) as SelectedChangedBehaviour
;
if (behavior
== null)
{
behavior
= new SelectedChangedBehaviour
(element
);
element.
SetValue(SelectedIndexChangedBehaviourProperty, behavior
);
}
return behavior
;
}
private static void OnSetCommandParameterCallback
(DependencyObject dependencyObject, DependencyPropertyChangedEventArgs e
)
{
ListBox listbox
= dependencyObject
as ListBox
;
if (listbox
!= null)
{
SelectedChangedBehaviour behavior
= GetOrCreateBehavior
(listbox
);
behavior.
CommandParameter = e.
NewValue;
}
}
public static SelectedChangedBehaviour GetSelectedIndexChangedBehaviour
(DependencyObject obj
)
{
return (SelectedChangedBehaviour
)obj.
GetValue(SelectedIndexChangedBehaviourProperty
);
}
public static void SetSelectedIndexChangedBehaviour
(DependencyObject obj, SelectedChangedBehaviour value
)
{
obj.
SetValue(SelectedIndexChangedBehaviourProperty, value
);
}
public static readonly DependencyProperty SelectedIndexChangedBehaviourProperty
= DependencyProperty.
RegisterAttached("SelectedIndexChangedBehaviour",
typeof(SelectedChangedBehaviour
),
typeof(SelectedChanged
),
null);
}
}
Essentially this consists of a Dependency Property for the command and another one for the CommandParameter. The last part is to actually bind to it in XAML. First add the namespace to the xaml file
xmlns:xt="clr-namespace:PrismExtension.CommandBehaviours;assembly=PrismExtension"
Then in a control that is derived from ListBox this is the code I have used to bind the command to the control
<ListView Name="notesListView"
xt:SelectedChanged.Command="{Binding SelectedNoteCommand}"
xt:SelectedChanged.CommandParameter="{Binding ElementName=notesListView}">
On my viewmodel for the view I have a command called SelectedNoteCommand exposed as a read-only property which is the command that the control will fire on the selected item changing.
I pulled this together from a couple of sources – one is the click command itself from inside the Prism code. The second was a really informative video found here by Erik Mork of Silver Bay Labs. Also worth checking out if you are playing around with CommandBehaviours is nRoute because here you will find implementations of a whole swathe of CommandBehaviours! In fact check out nRoute anyway, as the guy writing it is a freaking Genius! The Office 2010 demo app is just beautiful.
PeteDoesStuff.NET .Net, Prism, WPF mvvm, Prism, WPF
This is how I am structuring my Prism projects.
ProjectName
This is the project which contains the shell and bootstrapper.
ProjectName.Infrastructure
This project contains all the classes that are shared between the modules such as events and common interfaces.
ProjectName.Infrastructure.Resources
In this project I put all my resources for the project such as styles and images. This allows me to share specific icons and pictures etc between the different modules.
ProjectName.ModuleName
These projects are the modules loaded by the bootstrapper. Inside the project I have a separate folder for Views and one for ViewModels. The module class lives in the route of the assembly. I currently am separating out each area of functionality into separate modules though there has been discussion as to whether you should have a Core Module which holds most or all the core functionality of the app. I am against this as I think the notion of having more than 1 area of functionality in the one module does away with the advantages of modularity and increases the likelihood of having to do a full deployment when changing a single area of functionality.
PrismExtensions
This project contains my extensions for Prism or base code that helps speed up development. So far it has a couple of RegionAdapters, the start of an MVVM framework and a custom bootstrapper that loads all the extensions automatically.
PeteDoesStuff.NET Prism, WPF Prism, WPF
After playing with Prism I have decided the next thing to look at is Onyx. This is a MVVM framework for WPF written by Bill Kempf. The best tutorial I have found on it so far is by Sacha Barber on CodeProject (WPF:FlipTile 3D) and these notes are based on my interpretation of his code.
The View-ViewModel interaction is setup declaratively in the XAML for the view as illustrated below:
<window title="TestWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
width="300"
height="300"
xmlns:local="clr-namespace:OnyxApp"
xmlns:onyx="http://schemas.onyx.com/2009/fx/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
x:class="OnyxApp.TestWindow"
onyx:view.model="{x:Type local:TestWindowViewModel}">
The TestWindowViewModel class here is coded as below
namespace OnyxApp
{
public class TestWindowViewModel:ViewModel
{
public TestWindowViewModel(View view):
base(view)
{}
As far as I can see, this is the minimum amount of code to get the MVVM interaction going.
PeteDoesStuff.NET Onyx, WPF mvvm, Onyx, WPF
Creating a modular application using Prism V2 – Screencast 3/4 : Implementing views and services
Step 5 – Creating the ViewModel
- View model contains all the bindable elements that will appear in the view.
- Use a ViewModel to allow easy testing and styling.
- Just a normal class exposing data via properties.
- Use constructor injection to add the ViewModel to the View and set the View’s DataContext to be the ViewModel.
- Add HeaderData property to the ViewModel – if being used in tabs.
Step 6 – Implementing Services
- Create interface for service to allow testing in isolation/swapping of concrete types etc.
- Add service interface to constructor for ViewModel using constructor injection.
- Initialise data using the service interface.
- Add the unity container to the constructor for the module class.
- In the module initialisation code register the Service with the unity container using the following code
container.RegisterType<IServiceInterface, ServiceClass>();
- If you want a singleton service use this instead
container.
RegisterType<IServiceInterface, ServiceClass
>(new ContainerControlledLifetimeManager
);
Creating a modular application using Prism v2 – Screencast 4/4 : Decoupled Communication
This video covered the event aggregator and how to publish/subscribe to loosely coupled events. Pretty much covered the same stuff as my post on event aggregation.
PeteDoesStuff.NET Prism, WPF Prism, WPF
I’ve been trying to collect together all the good resources I am finding on Prism. Here is some of what I have found so far.
Downloads
General Blogs/Blog Postings on Prism
Articles
CodeProject Stuff
Articles are now starting to popup on Code Project about Prism – heres the first few I have found
Webcasts
PeteDoesStuff.NET Prism, WPF Prism, WPF
There are 4 informative screencasts on Channel 9 on how to use Prism. These are my notes on the first 2.
Creating a modular application using Prism V2 – Screencast 1/4 : Creating a shell and modules
Step 1 – Create a Shell Project.
Key things about the shell project :
- This project contains the Unity Bootstrapper (assuming you are using Unity). This is a class inherited from UnityBootstrapper and is required by Prism to create the shell etc.
- Must override the CreateShell() method to return the shell for Prism to use.
- Override the GetModuleCatalog() method to return the list of available modules.
- To run the bootstrapper – create a new one in the application startup code and then run it.
Step 2 – Create a Module Project.
Key things about the module project:
- Module must expose IModule.
- Fill in implementation of Initialize()
- Ensure the module is added to the shell’s ModuleCatalog.
- Catalog.AddModule(typeof(module));
Creating a modular application using Prism V2 – Screencast 2/4 : Visual Composition
Step 3 – Adding Regions to the Shell
- Views in Prism sit within regions in the Shell.
- These regions are managed by the RegionManager.
- Add the namespace to the xaml file
xmlns:Regions=”clr-namespace:Microsoft.Practices.Composite.Presentation.Regions; assembly=Microsoft.Practices.Composite.Presentation”
- Then add to the xaml for the content hosting control you want the region to sit in the following
Regions.RegionManager.RegionName=”name of region”
Step 4 – View Discovery
- In the module project add a new user control to represent the view.
- To the constructor of the module add IRegionManager. This will automatically be resolved as Prism has previously registered the RegionManager with Unity.
- To the initialise method add the following
this.
regionManager.
RegisterViewWithRegion(“regionName”,
typeof(viewToInstantiate
));
PeteDoesStuff.NET Prism, WPF Free Resources, Learning, Prism, WPF
I recently decided to start looking at expanding my skills to include some of the new .NET 3.5 stuff. WPF looked the most interesting to start off with as its the new Windows Forms and also getting into the XAML and design side of .NET development looks like a good way to get my head around Silverlight. The learning curve so far hasn’t been nearly as steep as I was expecting – some of the things I was doing previously in Windows Forms now seem to be the MS-approved way of doing things now, such as the use of commands. I have found some really good free resources to help with picking up all the nuances
- The Official Microsoft WPF and Windows Forms Site – This site has loads of code downloads and some really good training videos. Most of the videos are pretty short and tell you how to do just one thing like how to use styles or perform layout. So once you have a basic understanding these are pretty good, easily digestible snippets to add to your knowledge.
- The WPF 08 Boot Camp – This site has the WPF boot camp course that was given by IdentityMine and various other people available to download for the grand price of free. I am about half way through this so far and its pretty darn good.
- Code Project – WPF Section – Lots of downloadable goodness here as well as some nice tutorials by Josh Smith (starting here) and Sacha Barber (starting here).
The next set of videos I am going to start watching is the WPF Soup to Nuts series.
I also purchased a number of books – expect some reviews of them in the future.
PeteDoesStuff.NET .Net, WPF Free Resources, Learning, WPF