Dynamically Building Windows Presentation Foundation DataTemplates

Since the early days of the personal computer revolution, the gap between what can be visualized in the imagination and what can be visually rendered by the typical application developer has been wide. The introduction of Windows Presentation Foundation (WPF) has greatly narrowed that gap. A rich visual experience is now within reach of any business application developer—no DirectX or DirectShow experience is needed.

Although the gap has narrowed, a learning curve still remains. The Windows SDK is flush with hundreds of samples covering every aspect of WPF from basic to advanced situations; it’s impractical to cover every scenario, especially more specialized edge cases. One of the more useful edge case scenarios is the dynamic DataTemplate. This article will show you how to dynamically build a DataTemplate and use the DataTemplate with a WPF control.

WPF and XAML

If WPF, Extensible Application Markup Language (XAML), DataTemplates, and Bindings are new terms to you, read on; otherwise, you can skip the next two sections.

A complete introduction to WPF development is beyond the scope of this article. So, this introduction will be confined to the DataTemplate and related concepts.

WPF is a data visualization engine built on top of familiar Microsoft technologies such as DirectX and DirectShow. As with other parts of the .NET framework, WPF is designed to make low-level libraries built into the Windows operating system more accessible to a developer. WPF richly renders all types of data, including media. The WPF development experience combines the best of what you may have seen in web development, embodied in XAML, with what you’ve seen in traditional Forms development, including drag-and-drop controls with properties.

In addition, WPF offers better and more consistent decoupling between the user interface and the business logic. So, for example, you can truly separate the user interface from the rest of the application.

Although WPF applications are bound to the Desktop, Silverlight hosts a subset of WPF in the browser for Rich Internet Applications.

You can find a more complete overview to WPF in the WPF documentation.

WPF allows you to code a complete application in XAML or purely in, for example, C#. Most WPF applications will combine the two coding methods, often expressing the more static parts of the application in XAML and the more dynamic pieces in C# or VB.NET.

DataTemplates and Bindings

Two of the core parts of WPF are Dependency Properties and Binding classes (Bindings). Dependency Properties and Bindings work together to move data out of business logic and into the user interface to be rendered by WPF.

Many of the WPF controls have Dependency Properties that allow a developer to create interdependencies between controls and underlying data. So, for example, a developer can express a relationship between a button’s color and the background color of the window it sits on. Once the relationship is established, runtime changes to the background of the Window with cascade to the button. The power of Dependency Properties is that you establish the relationship and WPF takes care of the rest.

Dependency Property relationships are expressed in a Binding. A Binding’s Path expresses where the Binding goes to get data. There are a myriad of ways to express and extend Bindings. Like Dependency Properties, the power of Bindings is that once you define the Binding in XAML or code, WPF handles the rest. The relationships between Dependency Properties and Bindings is depicted in Figure 1.

Figure 1: Relationship between Dependency Properties and Bindings

DataTemplates allow a developer to customize the “look” and “feel” of a control; this allows a developer to, for example, place controls within other controls. As I’ll show you later, a DataTemplate is assigned to a DependencyProperty and Bindings within the DataTemplate dictate where to go in the source object for data.

With the WPF introduction complete, I’m moving to some practical application of the features I’ve covered. First, I’ll explain how the sample works and then I’ll highlight the key parts of the sample code.

The Sample

The sample is straightforward. In the top of the window a user enters a SELECT statement for a table in the AdventureWorks database and then presses the button to generate a columned list of all the data in the select statement.

The code executes as follows:

  • The application generates a DataSet.
  • Then, it generates a DataTemplate based on the DataSet.
  • Next, it programmatically applies the DataTemplate to the listview control on the screen.
  • Finally, it loads the data into the listview.

Double-clicking on any row in the list will load the textbox at the bottom of the screen with the window.

Generating a DataTemplate

The following is the code generating the DataSet and DataTemplate.

ds = new DataSet();

adapter.Fill(ds);


ns = "xmlns=\"http://schemas.microsoft.com/winfx/2006/
              xaml/presentation\"";

   tempString.Append("<DataTemplate " + ns + ">");
   tempString.Append("<Grid>");
   tempString.Append("<Grid.ColumnDefinitions>");
   foreach (DataColumn col in ds.Tables[0].Columns)
   {
      tempString.Append("<ColumnDefinition Name=\"" +
         col.ColumnName + "\" Width=\"100\" />");
   }
   tempString.Append("</Grid.ColumnDefinitions>");
   for (int n = 0; n < ds.Tables[0].Columns.Count; ++n)
   {
      tempString.Append("<TextBlock Text=\"{Binding Path=[" +
         n.ToString() + "]}\" Grid.Column=\"" + n.ToString() +
         "\"");
      tempString.Append(" FontWeight=\"Bold\" />");
   }
   tempString.Append("</Grid>");
   tempString.Append("</DataTemplate>");

The line including the namespace is the most unusual part of the code. You may have noticed that this is the same namespace included when you create any XAML file in Visual Studio. Without the namespace, the code handling the XML data cannot validate the XAML.

A Grid View resource is also a good alternative to a DataTemplate to display data in a grid.

Following is a DataTemplate XAML snippet of what the Product table would look like with the first two fields in the select statement. Notice the Binding and Path statement in the TextBlock. In the example, the Path is assigned to the column in a particular Row in the DataSet.

<DataTemplate>
<Grid xmlns="http://schemas.microsoft.com/winfx/2006/
             xaml/presentation">
   <Grid.ColumnDefinitions>
      <ColumnDefinition Name="ProductID" Width="100" />
      <ColumnDefinition Name="Name" Width="100" />
   </Grid.ColumnDefinitions>
   <TextBlock Text="{Binding Path=[0]}"
              Grid.Column="0" FontWeight="Bold" />
   <TextBlock Text="{Binding Path=[1]}" Grid.Column="1"
              FontWeight="Bold" />
</Grid>
</DataTemplate>

Working with the Generated XAML

XAML is simply XML data. So, as you would guess, classes from the System.Xml namespace play a role. In this case, because a XamlReader Load function cannot accept a StringBuilder class, I created a XmlReader from the StringBuilder. The code appears below.

xml  = XmlReader.Create(sr);

temp = (DataTemplate)XamlReader.Load(xml);

The final steps assign the DataTemplate and data to the Listview control. Here is the code:

this.DataView.ItemTemplate = temp;
this.DataView.ItemsSource = _ds.Tables[0].Rows;

ItemTemplate and ItemsSource are both Dependency Properties. ItemsSource is the data to be rendered in the control. Collections assigned to ItemSource must have certain capabilites, but is not limited to the Rows on a DataTable. ItemTemplate is the DataTemplate to use to render the data in the control.

Inspecting a Row

In your solution, most likely you will want to inspect the data in a particular row. So, I added some code to copy the row data to a Textbox at the bottom of the screen when a user double-clicks a row in the ListView. The important thing to understand is that, underneath, a reference to the original data structure (DataRows) is maintained.

Conclusion

WPF leverages Windows; platform’s rich visualization with a productive development experience reducing development time yet, at the same time, producing engaging user interfaces. DataTemplates are one of many mechanisms developers can employ to customize the look of their application. The .NET Framework’s XML libraries and WPF classes make dynamically generating a DataTemplate easy.

Sources

More by Author

Get the Free Newsletter!

Subscribe to Developer Insider for top news, trends & analysis

Must Read