C# Silverlight - Using a DataGridTemplateColumn [Beginner]


Whenever you pit designers against developers, it always seems to be the developer that loses. It's very rare that controls like the Silverlight DataGrid are left alone - designers want little tweaks and polish to increase the user experience. This tutorial is going to illustrate how to use one of the most flexible solutions to theming a DataGrid - the DataGridTemplateColumn.

We'll be touching very little on the basics of how to use the Silverlight DataGrid. If you're new to the control.

The first thing we're going to do is build a default DataGrid without any styling. I created a class to hold some information about the SOTC authors and bound a collection of those to my DataGrid.
[silverlight width="400" height="300" src="BasicDataGrid.xap"]
using System.Collections.Generic;
using System.Windows.Controls;

namespace DataGridStyling
{
  public partial class Page : UserControl
  {
    public Page()
    {
      InitializeComponent();

      // Create some authors.
      List<Author> authors = new List<Author>()
      {
        new Author() 
        { 
          Name = "Brandon", 
          Username = "The Reddest", 
          Language = "C#"
        },
        new Author() 
        { 
          Name = "Charlie", 
          Username = "The Fattest", 
          Language = "ActionScript"
        },
        new Author() 
        { 
          Name = "Richard", 
          Username = "The Hairiest", 
          Language = "PHP"
        },
        new Author() 
        { 
          Name = "Mike", 
          Username = "The Tallest", 
          Language = "JavaScript"
        }
      };

      // Set the items source on the DataGrid to the
      // collection of authors.
      _dataGrid.ItemsSource = authors;
    }
  }

  /// <summary>
  /// Class to hold some information about an 
  /// SOTC author.
  /// </summary>
  public class Author
  {
    public string Name { get; set; }
    public string Username { get; set; }
    public string Language { get; set; }
  }
}

<UserControl x:Class="DataGridStyling.Page"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:dg="clr-namespace:System.Windows.Controls;assembly=System.Windows.Controls.Data"
    Width="400" Height="300">
  <Grid x:Name="LayoutRoot" Background="White">
    <dg:DataGrid x:Name="_dataGrid" 
                 AutoGenerateColumns="False">
      <dg:DataGrid.Columns>
        <dg:DataGridTextColumn 
          Binding="{Binding Name}" 
          Header="Name" 
          Width="100" />
        <dg:DataGridTextColumn 
          Binding="{Binding Username}" 
          Header="Username" 
          Width="100" />
        <dg:DataGridTextColumn 
          Binding="{Binding Language}" 
          Header="Language" 
          Width="100" />
      </dg:DataGrid.Columns>
    </dg:DataGrid>
  </Grid>
</UserControl>
 
All right, now let's starting using the DataGridTemplateColumn. This column type gives us the ability to set the template for normal cells and cells that are in edit mode. Here's the same example as above except that uses this column type on the Name column.

[silverlight width="400" height="300" src="TemplateColumn.xap"]
<dg:DataGrid x:Name="_dataGrid" 
             AutoGenerateColumns="False">
  <dg:DataGrid.Columns>
    <dg:DataGridTemplateColumn 
      Header="Name" 
      Width="100">
      <dg:DataGridTemplateColumn.CellTemplate>
        <DataTemplate>
          <TextBlock Text="{Binding Name}" 
                   Foreground="Green" 
                   FontWeight="Bold"
                   VerticalAlignment="Center"/>
        </DataTemplate>
      </dg:DataGridTemplateColumn.CellTemplate>
      <dg:DataGridTemplateColumn.CellEditingTemplate>
        <DataTemplate>
          <TextBox Text="{Binding Name, Mode=TwoWay}" />
        </DataTemplate>
      </dg:DataGridTemplateColumn.CellEditingTemplate>
    </dg:DataGridTemplateColumn>
    <dg:DataGridTextColumn 
      Binding="{Binding Username}" 
      Header="Username" 
      Width="100" />
    <dg:DataGridTextColumn 
      Binding="{Binding Language}" 
      Header="Language" 
      Width="100" />
  </dg:DataGrid.Columns>
</dg:DataGrid>
 
So as you can see, we changed the cell to display bold green text when not in edit mode, and a simple TextBox when it is in edit mode. This is accomplished by using the CellTemplate and CellEditingTemplate properties on the DataGridTemplateColumn object. I had to explicitly set the BindingMode to TwoWay so text entered into the TextBox would be committed back to my Author object.

Here's a slightly more interesting example that builds on the previous one. Now, whenever edit mode is entered, a pencil icon will be displayed to the left of the edit field.

[silverlight width="400" height="300" src="Pencil.xap"]
<dg:DataGrid x:Name="_dataGrid" 
             AutoGenerateColumns="False">
  <dg:DataGrid.Columns>
    <dg:DataGridTemplateColumn 
      Header="Name" 
      Width="100">
      <dg:DataGridTemplateColumn.CellTemplate>
        <DataTemplate>
          <TextBlock Text="{Binding Name}" 
                   Foreground="Green" 
                   FontWeight="Bold"
                   VerticalAlignment="Center"/>
        </DataTemplate>
      </dg:DataGridTemplateColumn.CellTemplate>
      <dg:DataGridTemplateColumn.CellEditingTemplate>
        <DataTemplate>
          <Grid>
            <Grid.ColumnDefinitions>
              <ColumnDefinition Width="Auto" />
              <ColumnDefinition Width="*" />
            </Grid.ColumnDefinitions>
            <Image Source="pencil_icon.png" 
                   Grid.Column="0" />
            <TextBox Text="{Binding Name, Mode=TwoWay}" 
                     Grid.Column="1" />
          </Grid>
        </DataTemplate>
      </dg:DataGridTemplateColumn.CellEditingTemplate>
    </dg:DataGridTemplateColumn>
    <dg:DataGridTextColumn 
      Binding="{Binding Username}" 
      Header="Username" 
      Width="100" />
    <dg:DataGridTextColumn 
      Binding="{Binding Language}" 
      Header="Language" 
      Width="100" />
  </dg:DataGrid.Columns>
</dg:DataGrid>
 
All I had to do in order to use the pencil icon was add it to my project like you would any other existing item. By default the Build Action property on the image will be set to Resource, which is what you want. Now, in XAML, you can simply reference the image by name.

There are basically no limits to how you can display information within cells using this column type. The powerful templating system behind Silverlight and WPF makes doing stuff like this trivial whereas before it may not have even been possible to accomplish the same task. On that note, that wraps up this introduction to the DataGridTemplateColumn.

Comments