First approach to Presentation Model with DataTemplates
May 21st, 2008
In my previous post I talked a little of a new way that WPF allows us to create (and inject) a view by using DataTemplates (or ControlTemplates). I talked about how the use of templates combined with the Presentation Model pattern can help you build fully testable applications.
I was contrasting the benefits of using Presentation Model against the Passive View’s flavor of the MVP pattern when using it in the WPF world. I want to clarify that the Stock Trader reference implementation that’s being shown with the Prism project is not using Passive View (it was in the very first drop, but not anymore)… it has a mix of MVP with Supervising Controller (as of today).
The spike made by the Prism team that I was talking about was released here (get the zip, and the spike is under the PublishedSpikes folder).
The spike was based on the existing UIComposition QuickStart, so not all the code there is related to DataTemplates (as I said, it is just a spike and not production code, but we thought it would be interesting to put it out there). You are very welcomed to check it out. I won’t use the same example as the spike in this post, as I want to focus only on the templating part and leave the rest out.
One very neat thing about using templates, is whenever you add a model into the Visual Tree, WPF will automatically inject the view (template), assign the model as it’s DataContext and render it on screen. How? Well, let’s see an example.
You first need to create the DataTemplate you want to use:
<DataTemplate DataType=”{x:Type models:OrderModel}”>
<StackPanel>
<Grid>
…
<Label Grid.Row=”0″ Grid.Column=”0″>Customer Name</Label>
<TextBox Grid.Row=”0″ Grid.Column=”1″ Text=”{Binding CustomerName}” />
</Grid>
<TabControl ItemsSource=”{Binding LineModels}” />
<Button Command=”{Binding SubmitOrder}”>Submit</Button>
</StackPanel>
</DataTemplate>
You could place this portion of XAML in the App.xaml as a resource, but if you do this for every view in one centralized place, that file can get very big, hard to read, hard to manage, and what is worst, all devs or designers will try to edit that file constantly at the same time. Furthermore, if you’re developing different modules (like what you could do with Prism), you will not be able to deploy the modules independently.
Best option: create separate ResourceDictionary files where you can put one or a few tamplates grouped logically. Later on, you can merge these resource dictionaries by using MergedDictionaries in the App.xaml as explained here.
“Ok now, but if I’m using Prism, I cannot accomplish decoupled modules if now my application class has to know about all the resource files in all my modules!”. Fortunately, all that can be done in XAML can be done programatically, so instead of using MergedDictionaries on App.xaml, you could have your Module initialization logic to merge the isolated dictionaries into the application wide ResourceDictionary. In the spike published by the Prism team, this is done with the following code:
dictionary.Source = new Uri(“pack://application:,,,/OrdersModule;Component/OrdersRD.xaml”);
Application.Current.Resources.MergedDictionaries.Add(dictionary);
Now that the initialization has being done, all you need to do is “show” this model. For example:
mainWindow.Content = new OrderModel();
mainWindow.Show();
On the next posts I’ll try to gather a downloadable sample, and show how to use commands to work in these scenarios. Also I’ll show how to use two-way bindings to communicate actions from the view to the model when commands are not enough.