PRISM, also known as Composite WPF, has established itself as a very popular framework for building modular, scalable Silverlight applications. A newer contender, the Managed Extensibility Framework (MEF), has also grown in popularity. In fact, these two frameworks have left people scratching their heads wondering which one to use, when, how, and why.
Download the source code for this project.
Special note: the source won’t run “as is.” You need to take two steps: first, right click the PRISMMEF.Web
project and choose, “set as start project.” Second, right click the PRISMMEFTestPage.aspx
and choose “set as start page.” Then the project will run fine.
MEF will be packaged with Silverlight 4, and indeed has several preview releases available that will work on Silverlight 3 and 4. PRISM is coming out with newer releases that embrace the MEF framework. In fact, both frameworks work well together and know how to talk to each other’s containers.
In this series of posts I want to explore some concepts and aspects of solving the Silverlight application problem using both PRISM and MEF. I will use PRISM primarily for its ability to integrate views into regions, to dynamically load modules, and to provide an abstract messaging contract with the event aggregator. MEF will be used for extensibility and to really tap into the ability to go out, find exports, and glue them into imports.
My primary goal in this short series will be to establish patterns for binding the view model to the view, and to dynamically load views and modules. We’ll look at how to do this in the current version of Silverlight 3. It’s important to note that future MEF releases may address some of the issues I tackle here and will make some workarounds obsolete, so stay tuned with that. I also want to express my sincere gratitude to Glenn Block (or, if you prefer, @gblock), a key member of the MEF team (and former member of the PRISM team, I believe, as well) for helping me with some of these examples and providing invaluable insights related to the inner workings of MEF.
Today we’re going to leave MEF to the side and focus on what PRISM and the IoC container that comes with it, Unity, provide. The challenge is something I see discussed quite often, and that is how to meld the view model and the view together. Some people seem to abhor using code-behind at all, so I want to tackle a few solutions to this while also providing my own pragmatic way that, ahem, does use a little bit of code behind (and explain why I really don’t care).
So, let’s get started. We’re going to have three main views today. The first will be the outer shell, which binds to a message and a button to dynamically load a second module. The module will have a second view that, in turn, will activate a third view. I am also going to show you three ways to bind your view model to your view using Unity. I will use view models with depedencies because these are the ones that cannot be referenced directly in XAML because the XAML parser doesn’t implicitly know how to resolve dependencies.
The pattern for establishing a PRISM project is fairly well-established by now. We create a new Silverlight Application, blow away the default user control provided, then make a shell and a bootstrapper class that inherits from UnityBootstrapper
.
I’ll also add a class project called “common” to hold interfaces, base clases, and other services or parts that are used by the entire application.
In common, we’ll define our service behavior. This could be wired to a “real” service but for now is just a mock one to demonstrate how these various methods work. The service contract looks like this:
public interface IService { void GetStuff(Action<List<string>> action); void GetMoreStuff(Action<List<string>> action); }
I’m using the method outlined in Simplifying Asynchronous Calls in Silverlight Using Action. We call the service, and send it a method to call back on us with the returned value. In this case, it is just two different lists of strings.
I created a separate project “service” to implement the interface. The code is simple, and is also the first place I use a little MEF. I’m simply exporting the service so that if I want to use MEF to import it, I can. Today we’ll let Unity wire it up and I’ll show you how.
The service implementation is straightforward. Again, we’ll add some MEF so it’s ready when we look into it. In this case, instead of calling a “real” service, I just hit the callback with a pre-determined list of numbers that most will recognize. The second method does the same, only in Spanish. The class looks like this:
[Export(typeof(IService))] public class Service : IService { public void GetStuff(Action<List<string>> action) { action(new List<string> { "One", "One", "Two", "Three", "Five", "Eight", "Thirteen" }); } public void GetMoreStuff(Action<List<string>> action) { action(new List<string> { "Uno", "Uno", "Dos", "Tres", "Cinco", "Ocho", "Trece" }); } #endregion }
Method 1: Provider
So now we can work on our view models. The main shell simply shows a title and exposes a button to click to dynamically load another module. The model looks like this:
public class ShellViewModel { const string APPLICATION = "This is the PRISM/MEF project demonstration."; public ShellViewModel(IModuleManager moduleManager) { ModuleCommand = new DelegateCommand<object>(o => { moduleManager.LoadModule("Module"); }); } public ShellViewModel() { } public string Title { get { return APPLICATION; } } public DelegateCommand<object> ModuleCommand { get; set; } }
Our problem with instantiating this in XAML is that the XAML parser doesn’t understand how to resolve the dependency for IModuleManager
. This is needed because I am going to dynamically load another module when you click the button bound to the ModuleCommand
. As I mentioned, there are several ways to make the glue and one way is to use a provider.
The provider is a base class which has only two purposes. First, it is typed to a class so that multiple view models will generate multiple type instances. We need this so we can have different ways to resolve our classes. Second, it exposes a mechanism to resolve our models. In this way, I’m not tightly coupled to Unity. I recognize that there has to be some external force supplying me with the object to resolve dependencies, but I’ll hold off on understanding just what that is.
This leaves me with something like this:
public abstract class ViewModelProviderBase<T> : INotifyPropertyChanged where T: class { public static Func<T> Resolve { get; set; } public ViewModelProviderBase() { T viewModel = Resolve(); if (viewModel != null) { _viewModel = viewModel; } } private T _viewModel; public T ViewModel { get { return _viewModel; } set { _viewModel = value; OnPropertyChanged("ViewModel"); } } protected void OnPropertyChanged(string propertyName) { PropertyChangedEventHandler handler = PropertyChanged; if (handler != null) { handler(this, new PropertyChangedEventArgs(propertyName)); } } #region INotifyPropertyChanged Members public event PropertyChangedEventHandler PropertyChanged; #endregion }
So what we have is a base class typed to something. It exposes a static method to resolve that something. This is why the generic type works, so we have one method for resolution per type. It holds a reference to “whatever” and exposes it in the ViewModel
property, all the while playing nice with the property changed notifications to update any bindings. What does this buy us?
Now, to resolve my main view model, I can create a provider like this:
public class ShellViewModelProvider : ViewModelProviderBase<ShellViewModel> { }
Fairly straightforward, now we have a typed instance. In my bootstrapper or somewhere that “knows” what I’ve chosen to manage my objects, I can assign the resolver function like this:
ShellViewModelProvider.Resolve = Container.Resolve<ShellViewModel>;
Now the provider knows how to ask for a new instance of the type, with all dependencies sorted out. Then, in the XAML, we can simply bind the view model with no code behind by pointing to the provider, like this:
<UserControl.Resources> <vm:ShellViewModelProvider x_Key="ViewModelProvider"/> </UserControl.Resources> <Grid x_Name="LayoutRoot" DataContext="{Binding Source={StaticResource ViewModelProvider},Path=ViewModel}">
The resource creates a new instance of the provider. This calls to our resolver (in this case, the Unity container) and returns the view model, then binds it through the exposed ViewModel
property.
We’ve achieved a binding without code behind, but it feels a little “artificial.” While there wasn’t code behind, we did have to do some extra work up front to glue the resolver to the type. Let’s try something a little more natural in our dynamic module.
Method 2: View Injection
To me, this method feels like it makes the most sense. It is able to facilitate giving me objects and resolving dependency trees without the classes really knowing “how” it’s done. In the last example, we had a base provider that was a sort of liason and had knowledge of the model and the way the model is resolved. With constructor injection, you simply have a class and are given your concrete instances. You program to the interface, and don’t worry about how those interfaces were resolved. It’s the pure essence of a Unity pattern where the bootstrapper wires it up, then starts making objects and injecting what they need.
To make our dynamically loaded module, we add a new project as a Silverlight Application (this is important, it’s added as an application, not as a class library). I called this just “Module.” I can add all of the references that the parent project has, then right click and set “copy local” to false. The references will be there when the module is loaded, so doing this lets you code to the references without having a bloated XAP file. Most of the modular XAPs with dynamic PRISM are a few kilobytes as opposed to the 100K+ “main” XAPs that get generated due to this layering and reuse.
Set up a module catalog by adding a type of “Silverlight Resource Dictionary” which generates a XAML file with no code behind and a content type of “page.” You can change this to extend to the PRISM module namespace and declare your modules, like this (mine is in a subfolder called Modules, and I called the file ModuleCatalog.xaml
).
<m:ModuleCatalog xmlns_x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns_sys="clr-namespace:System;assembly=mscorlib" xmlns_m="clr-namespace:Microsoft.Practices.Composite.Modularity;assembly=Microsoft.Practices.Composite"> <m:ModuleInfoGroup Ref="PRISMMEF.Module.xap" InitializationMode="OnDemand"> <m:ModuleInfo ModuleName="Module" ModuleType="PRISMMEF.Module.ModuleInit, PRISMMEF.Module, Version=1.0.0.0"/> </m:ModuleInfoGroup> </m:ModuleCatalog>
Here, I’m giving the module all it needs: a name, the XAP it will load from, and how the assembly and types marry in. PRISM wants the type of the module class to call to initialize everything once the XAP file is loaded. You wire this type of catalog into PRISM by doing this in the bootstrapper:
protected override IModuleCatalog GetModuleCatalog() { return ModuleCatalog.CreateFromXaml( new Uri("PRISMMEF;component/Modules/ModuleCatalog.xaml", UriKind.Relative)); }
If you don’t remember, in the main view model we took in a reference to the module manager and wired a command to do this: moduleManager.LoadModule("Module");
. This causes the module manager to look up in the catalog, find the entry, note that it is not yet loaded, then pull in and parse the XAP. This is the dynamic loading.
Let’s hop over to the dynamically loaded module. This module is going to use the service and bind a list of controls to the first method (the one that returns numbers in English). The view model looks like this:
public class StuffViewModel : INotifyPropertyChanged { public StuffViewModel(IService service) { ListOfStuff = new ObservableCollection<string>(); service.GetStuff(stuff => { foreach (string thing in stuff) { ListOfStuff.Add(thing); } }); } private DelegateCommand<object> _dynamicViewCommand; public DelegateCommand<object> DynamicViewCommand { get { return _dynamicViewCommand; } set { _dynamicViewCommand = value; PropertyChangedEventHandler handler = PropertyChanged; if (handler != null) { handler(this, new PropertyChangedEventArgs("DynamicViewCommand")); } } } public ObservableCollection<string> ListOfStuff { get; set; } #region INotifyPropertyChanged Members public event PropertyChangedEventHandler PropertyChanged; #endregion }
A few things to notice here. First, there is a dependency on the service and when constructed, it will immediately call to the service to get the list of strings. Second, we have a command to dynamically load view (in this case, the view is loaded with the module, so a better term would be dynamically display the view), but we leave the resolution or implementation of the command up to external forces to decide.
Back in our Bootstrapper
class, I need to tell Unity how to resolve the service. I override ConfigureContainer
and give it this code:
protected override void ConfigureContainer() { base.ConfigureContainer(); Container.RegisterType&type;IService, Service.Service>(); }
Now Unity knows that when I ask for IService
, I want Service
.
In my new module, everything is set up in the ModuleInit
. This is the type referenced in the catalog, and also implements IModule
. We’re going to to do two key things here. First, we’ll take in a region manager and register the main view for this module. Second, we’re going to tell Unity how to give us the view we’ll show dynamically when we ask for it. This happens here:
public class ModuleInit : IModule { IRegionManager _regionManager; public ModuleInit(IUnityContainer container, IRegionManager regionManager) { container.RegisterType<UserControl, DynamicView>("DynamicView"); _regionManager = regionManager; } #region IModule Members public void Initialize() { _regionManager.RegisterViewWithRegion("MainRegion", typeof(StuffView)); } #endregion }
Don’t worry about the DynamicView
control just let. We set up Unity to say, “If I want a UserControl, labeled DynamicView, give me the DynamicView type.” We could just as easily made the label “foo” and provided the type “bar”. The module initializer is a great place to configure the parts of the container specific to that module. The StuffView
is what is displayed.
You’ve seen the view model, so let’s talk about the view. The XAML looks like this:
<Grid x_Name="LayoutRoot" Background="White"> <Grid.ColumnDefinitions> <ColumnDefinition/> <ColumnDefinition/> </Grid.ColumnDefinitions> <ListBox ItemsSource="{Binding ListOfStuff}"/> <Button Grid.Column="1" Content="Add View" cal:Click.Command="{Binding DynamicViewCommand}"/> </Grid>
Two columns, one for the list of stuff, and the other a button to show the next view.
How do we glue our view model? As I mentioned, this does involve code behind but makes the most sense to me. We take advantage of the way Unity resolves dependencies and code our view like this:
public partial class StuffView : UserControl { public StuffView() { InitializeComponent(); } public StuffView(StuffViewModel viewModel, IUnityContainer container) : this() { LayoutRoot.DataContext = viewModel; viewModel.DynamicViewCommand = new DelegateCommand<object>(o => { container.Resolve<IRegionManager>().RegisterViewWithRegion("MainRegion", () => container.Resolve<UserControl>("DynamicView")); }); } }
We could do this with properties and attribute them with the Dependency
attribute as well. In this case, we reference the view model so it is wired in by Unity with any dependencies. Because we get the container, we’re also able to resolve the IRegionManager
and tell it to add the dynamic view to the region when the command is executed. Notice that here we are resolving UserControl
, which we set up in the module initialization function. The important part is that my view doesn’t have to understand how a region manager does what it does or know what the other view is, it simply calls the contract and passes along what the container resolves for us.
Of course, that command is not going to do much unless we have the actual view.
The dynamic view will share the same view model and show the same list for the sake of simplicity, but I wanted to show another way of wiring the view model to the view.
Method 3: Behaviors
Again, our challenge is that XAML doesn’t know how to resolve dependencies. So, we can use constructors or decorated properties and let Unity wire them in, or create our own constructs that have to be notified about what to do and then supply the needed classes.
This method uses an attached property to create the view model and attach it to the view. This time instead of keeping it overly generic, I went ahead and referenced the unity container. The behavior needs to be wired up with the container so it can resolve view models, but the view model type is passed dynamically.
The behavior looks like this:
public static class ViewModelBehavior { // this is the part I like the least, could abstract it // but this example is long enough already! public static IUnityContainer Container { get; set; } public static DependencyProperty ViewModelProperty = DependencyProperty.RegisterAttached( "ViewModel", typeof(string), typeof(ViewModelBehavior), new PropertyMetadata(string.Empty, new PropertyChangedCallback(OnModelAttached))); public static string GetViewModel(DependencyObject obj) { return obj.GetValue(ViewModelProperty).ToString(); } public static void SetViewModel(DependencyObject obj, string value) { obj.SetValue(ViewModelProperty, value); } public static void OnModelAttached(object sender, DependencyPropertyChangedEventArgs args) { FrameworkElement element = sender as FrameworkElement; if (element != null) { if (args.NewValue is string) { string viewModelContract = args.NewValue.ToString(); if (!string.IsNullOrEmpty(viewModelContract)) { Type type = Type.GetType(viewModelContract); element.DataContext = Container.Resolve(type); } } } } }
So what’s interesting here is that we have a reference to the unity container, and what happens when the property is attached. It is expecting a fully qualified type passed in a string. We use the Type
class to resolve the type, then use the containe to resolve the instance and bind it to the data context of the element that had the behavior attached.
This leaves our code-behind clean:
public partial class DynamicView : UserControl { public DynamicView() { InitializeComponent(); } }
And gives us flexibility to use the behavior to wire in whatever we want in the XAML:
<Grid x_Name="LayoutRoot" Background="White"> <Grid.RowDefinitions> <RowDefinition/> <RowDefinition/> </Grid.RowDefinitions> <TextBlock Text="This list was bound using the behavior."/> <ListBox Grid.Row="1" vm:ViewModelBehavior.ViewModel="PRISMMEF.Module.ViewModel.StuffViewModel, PRISMMEF.Module, Version=1.0.0.0" ItemsSource="{Binding ListOfStuff}"/>
Notice the fully qualified view model type on the ListBox, which uses the behavior to resolve and then bind the view model. Wrapping Up
What we can do now is show a view with a button that was bound with no code behind and let Unity wire in dependencies. Clicking the button dynamically loads a new module that takes in a service reference, calls the service, and shows items returned from the service. This is wired in and bound in the code behind and uses constructor injection. This new view then displays the list next to a button that adds another view, bound to the same list.
All of these scenarios require a bit of work to get where we need to go. Will MEF give us something better? Perhaps. Next post, I will explore why out of the box in Silverlight 3 we can’t simply glue pieces together using MEF without digging into the internals and providing some infrastructure. Much of that infrastructure will be out of the box in future versons, but this will help us understand what is going on behind the scenes. We will set up the infrastructure in anticipation of using MEF, then the third and final installment will involve another dynamically loaded module that wires it all together using MEF with a little help from Unity.
Stay tuned!
Download the source code for this project.
Special note: the source won’t run “as is.” You need to take two steps: first, right click the PRISMMEF.Web
project and choose, “set as start project.” Second, right click the PRISMMEFTestPage.aspx
and choose “set as start page.” Then the project will run fine.