Introduction
Like many people, I struggled to get to grips with WPF because it seemed so "alien" when programming a desktop based application. It seemed so different, and I just couldn't apply knowledge that I already had - and then one day, it hit me. I'd been approaching this from the wrong angle, completely. By applying thinking from ASP.NET, I could relate what I knew to WPF. Obviously, WPF offered so much more, but it gave me a head-start.
We aren't going to go too deep into WPF. I'm going to show the same application written in ASP.NET and WPF, and we'll take a look at how the different parts of the code relate. We'll also take a look at some of the ways that WPF is fundamentally different, even though, superficially, it looks the same.
This article is not aimed at examining the differences between programming stateless and stateful applications. We aren't going to concern ourselves with worrying about issues such as round-trips and maintaining state.
Overview
Before we go any further, let's take a look at the application we're going to create. It's a simple application that reads data from an XML file and displays it in a list. There's nothing complicated going on in it, and we are going to accomplish all the "clever" stuff. The data that we are going to bind to looks like this:
="1.0" ="utf-8"
<People>
<Person Name="Josh" Handle="RockStar" IQ="10000" />
<Person Name="Sacha" Handle="The Bloginator" IQ="10000" />
<Person Name="Karl" Handle="The MoleMan" IQ="10000" />
<Person Name="Pete" Handle="Pretender to the throne" IQ="10" />
</People>
The ASP.NET application looks like this:
The WPF application looks like this:
The ASP.NET application
The code for the ASP.NET application is shown here:
<%@ Page Language="C#" AutoEventWireup="true"
CodeFile="Default.aspx.cs" Inherits="_Default" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
<title>Sample App</title>
<style type="text/css" media="all">
td
{
font-family : Tahoma;
font-size : 10px;
}
.iqStyle
{
font-family : Verdana;
font-size : 14px;
font-style : italic;
}
</style>
</head>
<body>
<form id="form1" runat="server">
<div>
<asp:GridView ID="GridView1" runat="server" AutoGenerateColumns="False"
DataSourceID="XmlDataSource1" ShowHeader="False">
<Columns>
<asp:BoundField DataField="Name" />
<asp:BoundField DataField="Handle" />
<asp:BoundField DataField="IQ" ItemStyle-CssClass="iqStyle" />
</Columns>
</asp:GridView>
</div>
<asp:XmlDataSource ID="XmlDataSource1" runat="server" DataFile="~/Sample.xml"
XPath="/People/Person"></asp:XmlDataSource>
</form>
</body>
</html>
As you can see, there's not a lot to it. Basically, we create an XmlDataSource
and bind it to a GridView
. There are a couple of styles that we've added manually to control formatting, but there is no clever code going on here. The binding is all taken care of here for us.
The WPF application
Now, let's take a look at the code for the WPF version:
<Window
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2006"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" mc:Ignorable="d"
x:Class="WpfSampleApp.Window1"
x:Name="Window"
Title="Sample App"
Width="380" Height="240">
<Window.Resources>
<XmlDataProvider x:Key="PeopleSource" d:IsDataSource="True" Source="Sample.xml"/>
<Style TargetType="ListBox">
<Setter Property="Control.FontFamily" Value="Tahoma" />
<Setter Property="Control.FontSize" Value="10" />
</Style>
<Style x:Key="FontStyle">
<Setter Property="Control.FontFamily" Value="Verdana" />
<Setter Property="Control.FontStyle" Value="Italic" />
<Setter Property="Control.FontSize" Value="12"/>
</Style>
<DataTemplate x:Key="PersonTemplate">
<Grid>
<Grid.RowDefinitions>
<RowDefinition/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition/>
<ColumnDefinition/>
<ColumnDefinition/>
</Grid.ColumnDefinitions>
<TextBlock Width="40" Grid.Column="0"
Text="{Binding Mode=OneWay, XPath = @Name}" />
<TextBlock Width="130" Grid.Column="1"
Text="{Binding Mode=OneWay, XPath=@Handle}" />
<TextBlock Width="Auto" Grid.Column="2"
Text="{Binding Mode=OneWay, XPath = @IQ}"
Style="{StaticResource FontStyle}" />
</Grid>
</DataTemplate>
</Window.Resources>
<Grid x:Name="LayoutRoot">
<ListBox Padding="3" HorizontalAlignment="Left" Width="Auto"
ItemTemplate="{DynamicResource PersonTemplate}"
ItemsSource="{Binding Mode=Default, Source={StaticResource PeopleSource},
XPath=/People/Person}" VerticalAlignment="Top" Height="Auto"/>
</Grid>
</Window>
I used Expression Blend to put this together (hint - if you're serious about WPF, then you really need to get a copy of Blend; it makes your life so much easier). It uses an XmlDataSource
to bind to a ListBox
, which we're going to format to display the data from the XML file. Again, notice that I haven't had to write a single line of C# - it's all done in the XAML.
Styles
As mentioned before, we created a couple of styles in the ASP.NET application. Similarly, we created a couple of styles in the WPF application, which do roughly the same thing. In this section, we're going to take a look at the two types of styles we created.
Type selectors
In CSS, a type selector allows you to match a style to every instance of this type in the document tree. So, we're going to change the font of every TD
element to 10px Tahoma.
WPF allows you to do the same by creating a style that is applied to a particular TargetType
. In our example, we change the font of every ListBox
in the window to size 10 Tahoma.
Careful readers will notice that I didn't say that the size of the font in the ListBox
is 10 pixels. Here's one of the first changes to get your head round in WPF, namely the fact that WPF is resolution independent. This means that we no longer think of things in terms of pixels - so, a 1 inch button on a 96DPI monitor will be a 1 inch button on a 140DPI monitor.
Named styles
In the ASP.NET application, we created a named style that changed the font to 12px Italic Verdana. Again, WPF allows us to set a named style that changes the font to size 12 Italic Verdana. In order to apply the style in ASP.NET, we used ItemStyle-CssClass="iqStyle"
. Applying the style in WPF is similarly easy; here we use Style="{StaticResource FontStyle}"
. The {...}
section utilises binding to actually apply the values - the StaticResource
provides references to previously loaded resources, so is useful here for inline styles. WPF does allow you to create the equivalent of external stylesheets. Josh Smith has provided excellent tutorials on using external resources. (My favourite is this one).
Data binding
In both applications, we are using XPath to retrieve the values from the XML. In both cases, we created a DataSource which linked to the XML file, and then said how we wanted to display it.
In ASP.NET, we declared that we wanted to use a set of BoundField
s to display each portion of the data.
The WPF we have used here is more powerful because we have separated out how we would like our items to be displayed from the container that will actually display it. This means that we can use the same template in different containers - thus maintaining consistency, and removing duplication. In the WPF code, the template is the portion in the DataTemplate
section. This states that we want to display one row of data per item, with three columns. Each item is displayed in a TextBlock
, which is a general purpose text class, and is bound to a particular element using one way data binding.
In our sample, the actual consumer of this DataTemplate
is the ListBox
. The ItemsSource
tells the runtime that we want to bind the data in the datasource to our listbox. As mentioned, the Grid in the DataTemplate
represents one row of data. The ItemTemplate
simply tells the application which template to apply on each row and, to a certain extent, could be thought of as being analogous to the RowDataBound
method on the GridView
. So, for each row of data, we're going to create a grid represented in the PersonTemplate
.
Conclusion
I hope that this article has whetted your appetite enough for you to want to start playing around with WPF. If you have experience in ASP.NET, then certain elements in WPF become a lot easier to understand. The team behind WPF has obviously learned a lot of lessons from ASP.NET, and has put this to good use. By thinking of WPF elements in terms of how applications are developed in ASP.NET, a lot of the concepts will suddenly fall into place. Obviously, I've glossed over a lot of the details about how to use WPF, and I'm not claiming that WPF should be used for web development, but it shows how that particular mindset can give you a head-start.
Possibly, the biggest initial hurdle you will face is getting familiar with how WPF utilises binding, which goes way beyond just binding to items in a database. Once you start to appreciate how it allows you to bind to just about anything in the application, you realise how much you can accomplish without having to write any C# (or VB.NET).
Suggested reading
I'm not going to link to articles, but can I suggest that you read the WPF articles by Josh Smith, Karl Shiflett, and Sacha Barber? They have produced some fantastic tutorials, aimed at all levels.