DATABASE

Silverlight : Binding Using a DataTemplate

11/17/2012 12:40:34 AM
1. Problem

You need to apply a custom UI to data and specify how various parts of a complex data structure are bound to various parts of your complex UI. You also need this representation encapsulated so that it can be reused across your application wherever the related data structure is employed.

2. Solution

Define a DataTemplate and specify appropriate bindings to bind parts of the backing data structure to elements of the data template. Apply the DataTemplate where possible to apply a consistent UI to the bound data.

3. How It Works

A DataTemplate offers a way to provide a repeatable and consistent visual representation for a portion or all of a specific application data source within your UI. It encapsulates a portion of your UI and can be defined in terms of any of the standard drawing primitives and controls available, as well any custom controls you might write. Appropriate bindings applied to various properties of the constituent elements ties the DataTemplate to the backend application data source that it aims to provide the UI for.

3.1. Declaring a DataTemplate

Listing 1 shows a simple DataTemplate that binds the Text properties of several TextBlock controls to properties in a CLR type.

Listing 1. A Simple DataTemplate
<DataTemplate x:Key="dtAddress">
  <Grid >
    <Grid.RowDefinitions>
      <RowDefinition Height="Auto"/>
      <RowDefinition Height="Auto"/>
    </Grid.RowDefinitions>
    <Grid.ColumnDefinitions>
      <ColumnDefinition Width="Auto" />
    </Grid.ColumnDefinitions>
    <TextBlock x:Name="tblkStreet" HorizontalAlignment="Stretch"
               VerticalAlignment="Stretch" Text="{Binding Street}"
               TextWrapping="Wrap" Foreground="White" FontSize="12"
               FontWeight="Bold"/>
    <StackPanel  Grid.RowSpan="1" Orientation="Horizontal" Grid.Row="1"
                 VerticalAlignment="Stretch">
      <TextBlock  x:Name="tblkCity" Text="{Binding City}"
                  TextWrapping="Wrap" FontSize="12"
                  FontWeight="Bold" Foreground="White"/>
      <TextBlock  x:Name="tblkComma" Text="," TextWrapping="Wrap"
                  Margin="2,0,2,0" FontSize="12" FontWeight="Bold"
                  Foreground="White"/>
      <TextBlock  x:Name="tblkState" Text="{Binding State}"
                  TextWrapping="Wrap" FontSize="12"
                  FontWeight="Bold" Foreground="White"/>
      <TextBlock  x:Name="tblkZip" Text="{Binding ZipCode}"
                  TextWrapping="Wrap" Margin="3,0,0,0" FontSize="12"
                  FontWeight="Bold" Foreground="White"/>
    </StackPanel>
  </Grid>
</DataTemplate>
				  

Note that a DataTemplate can be declared either as a resource that can be referenced using its x:Key value, as shown in Listing 1, or in place, as Listing 2 shows.

Listing 2. A DataTemplate Declared and Used in Place
<ContentControl x:Name="cntctrlEmployee" HorizontalAlignment="Stretch"
                VerticalAlignment="Stretch"
                Grid.Column="0" Background="Yellow" Margin="5,5,5,5"
                Height="200">
  <ContentControl.ContentTemplate>
    <DataTemplate>
      <TextBlock x:Name="tblkFirstName" Text="{Binding FirstName}"

TextWrapping="Wrap" FontSize="14" FontWeight="Bold"
                 Foreground="White" Margin="3,0,0,0"/>
    </DataTemplate>
  </ContentControl.ContentTemplate>
</ContentControl>

In Listing 4-5, you define and associate a DataTemplate to the ContentControl.ContentTemplate property in place. For in-place use, the DataTemplate is scoped to the containing element (in this case, the ContentControl.ContentTemplate) and is not available for use outside that scope.

You can also define a DataTemplate as a resource either in the resource section of the page or that of the application. In the former case, the DataTemplate is control scoped—that is, it is available for use anywhere on the MainPage (which is a UserControl). In the latter case, it is available for use anywhere in the entire application. In keeping with the rules, anything stored as a resource in ResourceDictionaries, such a DataTemplate, needs an x:Key defined so that it can be referenced for use via the StaticResource extension. 

3.2. Using a DataTemplate

So how do you use a DataTemplate? You can apply one to either a ContentControl (or a derived control, like Button) or an ItemsControl (or a derived control, like ListBox). To apply the DataTemplate, you set the ContentControl.ContentTemplate property or the ItemsControl.ItemTemplate property to the DataTemplate, as shown here:

<ContentControl  ContentTemplate="{StaticResource dtAddress}" />
<ListBox  ItemTemplate="{StaticResource dtAddress}" />

At runtime, the data bound to the ContentControl.Content property, or each data item in the data collection bound to the ItemsControl.ItemsSource property, is used to provide data for the bound properties in the DataTemplate.


4. The Code

Listing 3 shows code for the classes that provide the data for this sample.

Listing 3. Data Classes
namespace Recipe4_2
{
  public class Employee
  {
    public string FirstName { get; set; }

public string LastName { get; set; }
    public long PhoneNum { get; set; }
    public string ImageUri
    {
      get
      {
        return "/" + FirstName + ".png";
      }
    }
    public Address Address { get; set; }
  }

  public class Address
  {
    public string Street { get; set; }
    public string City { get; set; }
    public string State { get; set; }
    public int ZipCode { get; set; }
  }
}

Listing 4 shows the code to initialize the data, defined in the constructor of the MainPage class, in the codebehind file for the MainPage.

Listing 4. Data Initialization
using System.Collections.Generic;
using System.Windows.Controls;

namespace Recipe4_2
{
  public partial class MainPage : UserControl
  {
    public MainPage()
    {
      InitializeComponent();

      List<Employee> EmployeeList = new List<Employee>();

      EmployeeList.Add(new Employee
          {
            FirstName = "Joe",
            LastName = "Duffin",
            PhoneNum = 2125551212,
            Address = new Address { Street = "2000 Mott Street",

City = "New York", State = "NY", ZipCode = 10006 }
          });

      EmployeeList.Add(new Employee
          {
            FirstName = "Alex",
            LastName = "Bleeker",
            PhoneNum = 7185551212,
            Address = new Address { Street = "11000 Clover Street",
              City = "New York", State = "NY", ZipCode = 10007 }
          });

      EmployeeList.Add(new Employee
          {
            FirstName = "Nelly",
            LastName = "Myers",
            PhoneNum = 7325551212,
            Address = new Address { Street = "12000 Fay Road",
              City = "New York", State = "NY", ZipCode = 10016 }
          });

      cntctrlEmployee.Content = EmployeeList[0];
      itmctrlEmployees.ItemsSource = EmployeeList;
    }
  }
}

					  

You define two data templates, one each for the Address type and the Employee type in the MainPage.xaml file,

as shown in Listing 5.

Listing 5. DataTemplates for the Address and Employee Data Types
<UserControl.Resources>
  <DataTemplate x:Key="dtAddress">
    <Grid >
      <Grid.RowDefinitions>
        <RowDefinition Height="Auto"/>
        <RowDefinition Height="Auto"/>
      </Grid.RowDefinitions>
      <Grid.ColumnDefinitions>
        <ColumnDefinition Width="Auto" />
      </Grid.ColumnDefinitions>
      <TextBlock x:Name="tblkStreet" HorizontalAlignment="Stretch"

VerticalAlignment="Stretch" Text="{Binding Street}"
                 TextWrapping="Wrap" Foreground="White" FontSize="12"
                 FontWeight="Bold"/>
      <StackPanel  Grid.RowSpan="1" Orientation="Horizontal" Grid.Row="1"
                   VerticalAlignment="Stretch">
        <TextBlock  x:Name="tblkCity" Text="{Binding City}"
                    TextWrapping="Wrap" FontSize="12"
                    FontWeight="Bold" Foreground="White"/>
        <TextBlock  x:Name="tblkComma" Text="," TextWrapping="Wrap"
                    Margin="2,0,2,0" FontSize="12" FontWeight="Bold"
                    Foreground="White"/>
        <TextBlock  x:Name="tblkState" Text="{Binding State}"
                    TextWrapping="Wrap" FontSize="12"
                    FontWeight="Bold" Foreground="White"/>

        <TextBlock  x:Name="tblkZip" Text="{Binding ZipCode}"
                    TextWrapping="Wrap" Margin="3,0,0,0" FontSize="12"
                    FontWeight="Bold" Foreground="White"/>

      </StackPanel>
    </Grid>
  </DataTemplate>
  <DataTemplate x:Key="dtEmployee">
    <Grid Height="Auto" Width="300" Margin="5,5,5,5">
      <Grid.ColumnDefinitions>
        <ColumnDefinition Width="0.508*"/>
        <ColumnDefinition Width="0.492*"/>
      </Grid.ColumnDefinitions>
      <Grid.RowDefinitions>
        <RowDefinition Height="0.801*" />
        <RowDefinition Height="0.199*"/>
      </Grid.RowDefinitions>
      <Rectangle HorizontalAlignment="Stretch" Margin="0,−74.9660034179688,0,0"
                 Stroke="#FF000000" Grid.Row="1" Grid.RowSpan="1" RadiusX="3"
                 RadiusY="3" StrokeThickness="0" Fill="#FF9FA8E4"/>
      <Rectangle HorizontalAlignment="Stretch" Margin="0,0,0,0"
                 Grid.ColumnSpan="2" Grid.RowSpan="1" RadiusX="3"
                 RadiusY="3" Stroke="#FF686868" StrokeThickness="0"
                 Width="Auto">
        <Rectangle.Fill>
          <LinearGradientBrush EndPoint="0.5,1" StartPoint="0.5,0">
            <GradientStop Color="#FF000000"/>
            <GradientStop Color="#FF9FA8E4" Offset="1"/>
          </LinearGradientBrush>
        </Rectangle.Fill>
      </Rectangle>

					  

<Rectangle HorizontalAlignment="Stretch" Margin="3,3,3,3"
                 Stroke="#FF0A28EE" Grid.RowSpan="1"
                 StrokeThickness="5" VerticalAlignment="Stretch"/>
      <Image Margin="8,8,8,8" x:Name="imgEmployee"
              Source="{Binding ImageUri}"
              Stretch="Fill"
              HorizontalAlignment="Stretch" VerticalAlignment="Stretch"
              Grid.RowSpan="1"/>
      <StackPanel Margin="0,−0.114000000059605,0,0"  Orientation="Horizontal"
                  Grid.Row="1" Grid.ColumnSpan="1" VerticalAlignment="Stretch"
                  Grid.RowSpan="1">
        <TextBlock x:Name="tblkFirstName" Text="{Binding FirstName}"
                   TextWrapping="Wrap" FontSize="14" FontWeight="Bold"
                   Foreground="White" Margin="3,0,0,0"/>
        <TextBlock x:Name="tblkLastName" Text="{Binding LastName}"
                   TextWrapping="Wrap" FontSize="14" FontWeight="Bold"
                   Margin="3,0,0,0" Foreground="White"/>
      </StackPanel>
      <StackPanel Margin="0,0,0,0" Grid.Column="1">
        <ContentControl ContentTemplate="{StaticResource dtAddress}"
                        Content="{Binding Address}" Foreground="#FF0A28EE" />
        <TextBlock x:Name="tblkPhoneNum" Text="{Binding PhoneNum}"
                   TextWrapping="Wrap" FontSize="12" FontWeight="Bold"
                   Margin="0,5,0,0" Foreground="White"/>
      </StackPanel>
    </Grid>
  </DataTemplate>
</UserControl.Resources>

					  

You can see that a DataTemplate can, in turn, use another DataTemplate in a nested fashion. In dtEmployee earlier, you use a ContentControl to display an employee's address, and you reuse dtAddress as the ContentTemplate. This kind of reuse helps facilitate the consistency in UI representation of data, keeping in line with the promise of DataTemplates.

Applying the DataTemplate is simple. Let's apply it to a ContentControl like so

<ContentControl x:Name="cntctrlEmployee" HorizontalAlignment="Stretch"
                VerticalAlignment="Stretch"
                Grid.Column="0" Background="Yellow" Margin="5,5,5,5"
                ContentTemplate="{StaticResource dtEmployee}" Height="200"/>

					  

and bind it to the first Employee in the EmployeeList collection, as shown in the MainPage's constructor code in Listing 4-7, like so

cntctrlEmployee.Content = EmployeeList[0];

Figure 1 shows the DataTemplate in action.

Figure 1. DataTemplate in action in a ContentControl

Let's also apply the same DataTemplate to a ListBox, like so:

<ListBox x:Name="itmctrlEmployees"
         HorizontalAlignment="Stretch" VerticalAlignment="Stretch"
         Grid.Column="1"
         Width="325"
         ItemTemplate="{StaticResource dtEmployee}"
         Height="400"/>

Them, you bind it to the entire EmployeeList collection, as shown in the MainPage's constructor code in Listing 4, like so:

itmctrlEmployees.ItemsSource = EmployeeList;

This time, you see the DataTemplate being applied to each item in the ListBox but producing a consistent UI, as shown in Figure 2.

Figure 2. DataTemplate applied to ItemTemplate of a ListBox
Other  
  •  SQL Server 2005 : Advanced OLAP - Partitions, Aggregation Design, Storage Settings, and Proactive Caching
  •  SQL Server 2005 : Advanced OLAP - Actions
  •  SQL Server 2005 : Advanced OLAP - Key Performance Indicators (part 2) - KPI Queries in Management Studio
  •  SQL Server 2005 : Advanced OLAP - Key Performance Indicators (part 1) - A Concrete KPI, Testing KPIs in Browser View
  •  Oracle Database 11g : Database Fundamentals - Work with Object and System Privileges, Introduce Yourself to the Grid
  •  Oracle Database 11g : Database Fundamentals - Become Familiar with Other Important Items in Oracle Database 11g
  •  Microsoft ASP.NET 4 : Repeated-Value Data Binding (part 2) - Creating a Record Editor
  •  Microsoft ASP.NET 4 : Repeated-Value Data Binding (part 1)
  •  Microsoft ASP.NET 4 : Single-Value Data Binding
  •  SQL Server 2005 : Dynamic T-SQL - Dynamic SQL Security Considerations
  •  
    Video
    Top 10
    SG50 Ferrari F12berlinetta : Prancing Horse for Lion City's 50th
    The latest Audi TT : New angles for TT
    Era of million-dollar luxury cars
    Game Review : Hearthstone - Blackrock Mountain
    Game Review : Battlefield Hardline
    Google Chromecast
    Keyboards for Apple iPad Air 2 (part 3) - Logitech Ultrathin Keyboard Cover for iPad Air 2
    Keyboards for Apple iPad Air 2 (part 2) - Zagg Slim Book for iPad Air 2
    Keyboards for Apple iPad Air 2 (part 1) - Belkin Qode Ultimate Pro Keyboard Case for iPad Air 2
    Michael Kors Designs Stylish Tech Products for Women
    REVIEW
    - First look: Apple Watch

    - 3 Tips for Maintaining Your Cell Phone Battery (part 1)

    - 3 Tips for Maintaining Your Cell Phone Battery (part 2)
    Popular Tags
    Video Tutorail Microsoft Access Microsoft Excel Microsoft OneNote Microsoft PowerPoint Microsoft Project Microsoft Visio Microsoft Word Active Directory Exchange Server Sharepoint Sql Server Windows Server 2008 Windows Server 2012 Windows 7 Windows 8 Adobe Flash Professional Dreamweaver Adobe Illustrator Adobe Photoshop CorelDRAW X5 CorelDraw 10 windows Phone 7 windows Phone 8 Iphone