Using ViewModels and DataTemplates to compose your UI

Several drops ago we introduced a ViewModel composition spike. The purpose of this spike was to introduce a different way to compose your UI that WPF offers. That is instead of having your views and regions be UI-Elements, having them as pure models. What I mean by this is instead of having a Employee Region which is a tab, that contains EmployeeViews, you have a model (the region) that contains Employees. Likewise instead of of having a panel that displays a CustomerView, you have a  model that contains a single Customer. So how do I get my Employee region to display as a Tab, and my Employee to display itself in the same way as the EmployeeView? The answer is using DataTemplates. Using DataTemplates, you can define the UI rendering for a specific type (in this case the Employee and the EmployeeRegion). The nice thing for the no code-behind zealots among us is that there is absolutely NO CODE BEHIND in a DataTemplate.

Below you can see an example of what an Employee template might look like.

<DataTemplate DataType="{x:Type Employee}">
    <Grid x:Name="GeneralGrid">
        <Grid.ColumnDefinitions>
            <ColumnDefinition></ColumnDefinition>
            <ColumnDefinition Width="5"></ColumnDefinition>
            <ColumnDefinition Width="*"></ColumnDefinition>
        </Grid.ColumnDefinitions>
        <Grid.RowDefinitions>
            <RowDefinition></RowDefinition>
            <RowDefinition></RowDefinition>
            <RowDefinition></RowDefinition>
            <RowDefinition></RowDefinition>
        </Grid.RowDefinitions>
        <TextBlock Text="First Name:" Grid.Column="0" Grid.Row="0"></TextBlock>
        <TextBlock Text="Last Name:" Grid.Column="2" Grid.Row="0"></TextBlock>
        <TextBlock Text="Phone:" Grid.Column="0" Grid.Row="2"></TextBlock>
        <TextBlock Text="Email:" Grid.Column="2" Grid.Row="2"></TextBlock>
 
        <TextBox x:Name="FirstNameTextBox" Text="{Binding Path=FirstName}" 
            Grid.Column="0" Grid.Row="1"></TextBox>
        <TextBox x:Name="LastNameTextBox" Text="{Binding Path=LastName}" 
            Grid.Column="2" Grid.Row="1"></TextBox>
        <TextBox x:Name="PhoneTextBox" Text="{Binding Path=Phone}" 
            Grid.Column="0" Grid.Row="3"></TextBox>
        <TextBox x:Name="EmailTextBox" Text="{Binding Path=Email}" 
            Grid.Column="2" Grid.Row="3"></TextBox>
    </Grid>
</DataTemplate>

.csharpcode, .csharpcode pre
{
font-size: small;
color: black;
font-family: consolas, “Courier New”, courier, monospace;
background-color: #ffffff;
/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt
{
background-color: #f4f4f4;
width: 100%;
margin: 0em;
}
.csharpcode .lnum { color: #606060; }

Julian has a set of posts where he is discussing this interesting approach to composition. He’s done two posts so far, but I am sure there’s much more to come.

Using the Presentation Model in WPF

First approach to Presentation Model with DataTemplates

Great stuff!

This entry was posted in prism, WPF. Bookmark the permalink. Follow any comments here with the RSS feed for this post.
  • Mike

    Thanks for the reply…I’m VERY new to this whole MVx architecture and it’s got my head spinning…it seems the more I read, the more I become confused because everyone has a different opinion on how to implement a pattern…anyway…

    In the example above I could/would create a property called City on the EmployeeModel and then that property would be populated with a generic list that is created by a call to a datastore (via DAL) that would retrieve the list of cities?

    Thanks so much for responding…

  • http://www.codebetter.com/blogs/glenn.block/ Glenn Block

    Hi @Mike

    What you can do is hang your combo list off of your presentation model as a property, say a List, or a List Then just bind to it.

    Because its a ViewModel, you can decorate it with whatever it needs tot drive the UI.

  • Mike

    Great Post! Thanks for the samples…

    I do have one question however, if I need to have a combobox in my datatemplate, how would I go about setting it’s (the combobox’s) datacontext? I have created a couple of ObjectDataSources and added them to a separate ResourceDictionary and then in the datatemplate I simply bind the datacontext to one of those DataProviders. I’m sure there are other/better ways to do it, any suggestions? I guess all I’m really trying to do is populate that combobox with a list of states… (i.e. – CA, MN, NY, WI, Etc.)

  • http://www.codebetter.com/blogs/glenn.block/ gblock

    @Josh

    Great article. Thanks for the link.

  • http://www.codebetter.com/blogs/glenn.block/ gblock

    @Brett

    Check out the DelegateCommand. Using the command you can pass in delegates for the CanExecute and Execute.

  • Brett Ryan

    I’m on the hunt for a way to have capture events from this approach, specifically where an ItemsControl is used, like a ListBox, how do you capture a double click event, or better still, wire a Command=”{Binding ItemActivated”} action to be captured. I don’t care if it’s a global command I just want something, but at the moment I can’t figure anything out :(

    -Brett

  • http://joshsmithonwpf.wordpress.com Josh Smith

    This sounds about right to me. This is the “right” way to do data visualization in WPF, so I’m glad to see you guys are starting to do it as well.

    Check this out for another perspective: http://www.codeproject.com/KB/WPF/TreeViewWithViewModel.aspx
    Josh

  • http://www.bluespire.com/blogs Rob

    Now you’re starting to think like a WPF developer!!! You’ll find that this is what truly unlocks all of WPF’s possibilities.