indows Presentation Foundation (WPF) has been around for a couple of years now but there are still plenty of developers who don’t really know what it’s all about. Some think it’s a “Vista thing.” Others think it’s about transparent controls, shaded backgrounds, or separating user interface design from programming. I’ve even heard Microsoft MVPs (Most Valuable Professionals) take every attitude from “I don’t have time for bouncing buttons and spinning labels” to “it’s the wave of the future and every new application will be written with WPF by the end of the year.” (That was last year.)
There’s a kernel of truth in each of these statements but none of them really captures the full story. The truth is that WPF is increasingly important, and developers need to know what WPF is and understand its advantages and disadvantages.
When I started writing this article, I thought it would follow the usual pattern: Write a few examples, explain them, and then I’m done in a couple of days. After a couple weeks or experimenting and writing, however, the initial draft was already more than 24 pages long! There are so many new concepts and tools in WPF, that no one article can squeeze in everything with any detail.
So, rather than trying to cover everything thoroughly in one mammoth 50-page article, a more productive and usable approach is to write a series of articles. This one provides a quick introduction to WPF; it explains the basics and describes WPF’s advantages and disadvantages using simple, downloadable examples that demonstrate some of the features. The coverage is admittedly a mile wide and an inch deep. Later articles will describe particular features of WPF in greater depth.
|Author’s Note: I encourage you to experiment with the examples in Expression Blend, Visual Studio, or even as loose XAML pages in a browser.|
Before diving into a bunch of WPF examples, the following sections briefly explain what WPF is, what its goals are, and how you can obtain and use WPF. After you get WPF up and running, you’ll be able to follow along with the examples and make changes to experiment with the results.
A Brief Introduction to WPF
WPF has been available to developers for about three years now?but even developers who have worked with it have some trouble saying what it is. I’ve heard WPF described variously as:
- A graphical subsystem
- An application development framework
- A programming model
- A set of controls
- A method for separating user interface design and program code
- eXtensible Application Markup Language (XAML), pronounced “zammel”, a form of XML that Microsoft cooked up to represent WPF interfaces
- Microsoft’s Expression Blend product that you can use to design XAML interfaces
But probably the easiest way to understand WPF is to think of it as a collection of classes that simplify building dynamic user interfaces. Those classes include a new set of controls, some of which mimic old favorites (such as Label, TextBox, Button), and some that are new (such as Grid, FlowDocument, and Ellipse).
WPF also includes classes that support the new controls and provide new features, such as animation, new kinds of resources, and customizable behaviors. A WPF application uses an assortment of these objects to provide a user interface.
You can build this arrangement of objects in more than one way. First, you can use .NET code in C# or Visual Basic to create the objects one at a time, and glue them all together. This is a rather satisfying hands-on experience where you get to control exactly which objects are associated with which others?but it is rather difficult, partly because a user interface may require a lot of controls and partly because WPF requires a lot of extra non-visible objects to glue the controls together properly. Understanding how all these visible and invisible objects must fit together can be challenging.
Besides code, another way to build a WPF interface is to specify its content and controls in XAML.
Most developers are now familiar enough with XML to know that it’s a hierarchical language, with each element contained in a parent element. That makes XML a somewhat natural choice for user interface design, because user interfaces are more or less hierarchical, with controls containing other controls and some sort of window containing everything.
Here’s a XAML example that builds a simple WPF interface. The root element is a Window named winJustButtons. That element contains a Grid named LayoutRoot that has a blue background (FF0000FF). The Grid contains a yellow StackPanel named StackPanel1 that holds three Buttons. Don’t worry about the elements’ attributes and other details just yet, just look at the structure:
Figure 1 shows the resulting interface. You can see that the window contains the blue Grid, which contains the yellow StackPanel, which in turn contains the three Buttons.
|Figure 1. Hierarchical Heaven: XML works well to describe user interfaces because a user interface is hierarchical; a window contains controls that contain other controls.|
WPF and Silverlight
Silverlight (formerly known as WPF/e?the “e” stands for “everywhere”) is a restricted version of WPF designed to run securely in a browser while still providing a rich user interface. Because of the security restrictions, Silverlight does not provide all the features included in WPF. Some features are missing while others are provided in a restricted way.
You can learn more about the differences between WPF and Silverlight’s restricted version here.
The point to remember is that WPF is not XAML, XAML is just a language that you can use to define an interface built from WPF objects. However, it’s usually easier to use XAML to build those objects, and then load the XAML files into your projects.
Microsoft provides two tools for building programs that use XAML-defined interfaces: Visual Studio (VS) and Expression Blend (see the sidebar “Microsoft’s XAML Tools” for more information). Both VS and Blend use the same project format; you can seamlessly open and edit projects you create in one product with the other. Blend is primarily a design tool. It lets you build the WPF user interface, set properties on objects, defines styles, create animations for properties, attach animations to some property changes and events, and so forth.
VS does all this plus it lets you add code-behind to the project?the code that sits behind the user interface, providing business and navigation logic, event handlers for WPF controls, and control manipulation capabilities. Code-behind can create and execute WPF animations, build new controls, and do anything else that you can do interactively using the Blend or VS WPF designers.
Unfortunately, neither Blend nor VS is a perfect solution; each has its weaknesses. VS’s XAML IntelliSense is better than Blend’s (although neither handles quoted attribute values very well) and its toolbars and designer experience are easier to understand, particularly if you’re already used to VS. On the other hand, Blend provides a nice tool for building animations (you’ll see more about animations later) that VS lacks. If you’re using VS alone, you’ll have to write the XAML code for animations by hand. Each tool occasionally does something strange, and the XAML gets a bit messed up so it’s very useful to be able to modify the XAML by hand to remove property values, clear transformations, and generally check the sanity of the automatically-generated code.
Blend and VS also seem to understand XAML bugs in slightly different ways, so if you’re having problems, one tool may be able to provide a more meaningful error message than the other. That alone makes using the tools together a particularly powerful combination. In fact, Blend has a nice link to VS. Simply right-click on a window and select “Edit in Visual Studio” to open the file in VS. There’s a little strange synching of files as you move back and forth between the two applications but overall it works pretty well.
Microsoft’s intent is for graphic designers to use Blend to build the user interface and for programmers to use VS to write the code-behind. Unfortunately, while there are VS Express Editions, there is no Blend Express Edition?and at $499.00 it’s not a product everyone can afford. Many development groups cannot afford separate graphic designers and programmers, either.
If you don’t want to shell out almost $500, I recommend that you wait until you’re ready to really jump into WPF, download Blend’s free 30-day trial, and really give it a good workout. If you want to do a lot of animation, you may find it worth the cost. Meanwhile, you can use VS to get your feet wet.
Microsoft and enthusiastic developers can provide a long list of advantages for WPF. Some of these are really new and exciting. Others have been around for a long time in some form or another within VS.
The following sections briefly summarize some of the more widely trumpeted WPF capabilities.
This is a big one. WPF allows you to define animations that change an object’s property from one value to another over time. For example, you could change a Button’s Left position from 0 to 1000 over a one-second period to make the button move from the left edge of a window to a position 1000 pixels to the right.
Animations let you change positions, sizes, colors, opacities, transformation (scale, offset, or rotation), value, and so forth. The results are similar to those provided by Adobe Flash.
This feature is admittedly cool but for most applications it probably isn’t strictly necessary. I’ve written a lot of business applications over the years and I can’t think of a case where I thought, “Gee, I really wish I could make this button wiggle back and forth.”
When overused, animations can be distracting and annoying. Property animation is like cooking with haba?ero peppers: A little bit can add some spice but if you use too many you’re going to get burned.
|Figure 2. Terrific Transformations: WPF controls support simple rotation, scale, and skew transformations.|
This is another big one. WPF controls are built using the newer DirectX drawing library rather than the venerable GDI (Graphics Device Interface) and GDI+ tools used by Windows for so long. By using DirectX, WPF controls immediately get big improvements in rendering speed. They also get transformations, better multimedia support, and three-dimensional graphics. The next three sections describe these in a bit more detail.
WPF uses DirectX to allow you to transform just about anything in the user interface. That means you can translate, stretch, and rotate drawings, text, and controls relatively easily. The Transformations example program shown in Figure 2 uses simple transformations to rotate a Button -30 degrees, stretch a TextBox to three times its normal height, skew a Label by 30 degrees along the X axis, and horizontally flip a menu.
The following XAML code shows how the sample program Transformations builds its controls. The various transform objects (RotateTransform, ScaleTransform, and SkewTransform) give the controls in Figure 2 their unusual geometries.
I encourage you to download the example program and take a few minutes to experiment with the XAML transformation objects.
|Figure 3. Video Variety: Transformations even allow you to display video that has been scaled, rotated, or skewed.|
Better Multimedia Support
DirectX includes high-performance multimedia tools, so it’s natural to think that WPF might include improved multimedia support?and you won’t be disappointed. The TransformedVideo program example shown in Figure 3 uses MediaElement controls to display four copies of the same video. The XAML for the last three controls includes transformations so they display the video stretched, rotated, and skewed.
The following XAML code shows how this program defines the MediaElements shown in Figure 3. The first control shows the video in a normal manner. The others include transformations to scale, rotate, and skew the results.
As you can see, there’s no program code involved, just XAML. The MediaElement control provides simple methods for performing such actions as starting and stopping the media. It doesn’t get much easier than this.
One of the more impressive pieces of DirectX is Direct3D, a high-performance three-dimensional drawing engine. And when I say “high-performance,” I mean it. By using Direct3D, my 1.83 GHz dual-core laptop can draw tens of thousands of textured triangles moving in real time.
WPF uses Direct3D to make drawing three-dimensional scenes relatively easy. Drawing a scene with Direct3D using code is pretty complicated. WPF provides objects that simplify drawing considerably, although it’s still complicated.
One big weakness in Direct3D is that it requires you to figure out what graphics hardware the user has and take best advantage of it. Direct3D forces you to handle a bunch of unusual special cases (for example, if the graphics device becomes unavailable) and makes you build some complicated data structures.
|Figure 4. Cubist Art: WPF objects make drawing three-dimensional scenes easy…well…easier at any rate.|
With WPF you still need to build the data structures (they define the scene, after all) but WPF handles the setup and special cases for you. There seems to be a bit of a performance penalty but at least WPF makes this all easier.
Figure 4 shows a relatively simple program displaying a cube that has brick- and wood-textured surfaces. The program supplies horizontal and vertical scroll bars so users can change the viewing angle. Moving the scroll bars rotates the viewing camera around the X and Y axes by angles that bound to the scroll bars’ Value properties.
Unfortunately building three-dimensional models by hand is quite tedious and complex. For example, drawing the cube shown in Figure 4 took 358 lines of XAML code so it’s not shown here. You can download the example program and experiment with it if you like.
In Windows Forms graphics, you have two main choices for drawing something: either redraw it during a Paint event or draw it into a bitmap and then display the bitmap. In the first case, you need to redraw frequently, keeping track of whatever it is that you’re drawing. If parts of the drawing move over time, you need to keep track of where they all are during every redraw.
In retained-mode graphics, you define objects that represent parts of the drawing: lines, ellipses, text, images, and so forth. WPF automatically redraws any of them that need redrawing when they need it.
If you need one of the objects to move, you simply move it at the appropriate time. WPF automatically redraws the object in its new position as needed. Alternatively, you can define a WPF animation and let WPF move the object over time. Furthermore, because the objects draw themselves as needed, you can zoom in on them and they will redraw themselves with high precision, not the blocky appearance you would get from magnifying a bitmap.
Separate UI and Code-Behind
Using XAML to design a user interface and then writing separate code-behind files lets you distribute the work between user interface designers and VS programmers. Microsoft touts this as one of the great features of WPF?and if you have both designers and developers it is a great benefit, but it’s not a completely new concept. VS has allowed you to separate the user interface from code for years. The earliest versions of VS kept the user interface-building data and the code behind it in separate sections of the same file. You could let different developers work on different copies of this file and then paste them together later, although the process is a bit awkward.
Microsoft also advertises the declarative nature of XAML as one of its big benefits but they don’t say why that is a benefit. In some sense it seems reasonable that you should be able to specify a user interface that more or less just sits there using a declarative language that also just sits there.
However, when you throw in all the dynamic linking and animation that WPF supports, it’s clear that the user interface does a lot more than just sit there.
At some point, an interface can become so complicated that you’re practically forced to build it using a designer such as Expression Blend or VS rather than writing it in plain XAML. At that point, does it matter whether the interface is written in a purely declarative language or whether it’s stored as a series of commands for the program to automatically execute when it starts? In either case, your job is done after you design the user interface. You don’t need to write code to actually create it.
Declarative programming may be nice but when you’re using designers to build the interface anyway it’s a moot point.
Content Can Mean “Anything”
Many Windows Forms controls have a property that determines what they display. For example, Labels, TextBoxes, and Buttons all have a Text property. That property can hold text and nothing else.
In contrast, WPF controls typically have a special “content” property that determines what they contain. For a simple control such as a Label, this might just be some text. For a more complicated control such as a Grid or a StackPanel, the content might include a collection of child controls.
In fact, many WPF controls can contain all sorts of unexpected things in their content properties. For example, a Label typically contains a short piece of text?but you could just as easily fill it with a StackPanel holding an Image and another Label. (This would be an odd use for a Label but you could do it if you had the need.)
The following XAML code builds a button that contains a StackPanel, which holds an Image and a TextBlock. While the result looks different from a normal Button, it behaves exactly like a Button should.
|Figure 5. Creative Content: A control’s content property can contain just about anything.|
Figure 5 shows the sample GridInButton program displaying three buttons that don’t hold just plain text. The first two contain a StackPanel holding an Image and a TextBlock. The third holds a Grid with background set to a spider web picture, holding a TextBlock and six small pictures. All the buttons behave just like normal buttons.
WPF comes with several new controls for arranging content, including:
- StackPanel (arranges children in a single row or column)
- DockPanel (docks children to its edges)
- WrapPanel (arranges children in a row/column and wraps to a new row/column when it must)
- Grid (arranges children in rows and columns very flexibly)
Although the names may be unfamiliar, you’ll recognize some of these immediately, because they’ve been around for a while. For example, the (old) FlowLayoutPanel control does roughly what the (new) WrapPanel does and the (old) TableLayoutPanel serves a purpose similar to that of the (new) Grid control.
Some developers go on to say that these new controls change the way you design interfaces, and that using them you can allow the controls to take best advantage of the available space as a window resizes. However, good developers have already been doing that for years using arranging controls such as FlowLayoutPanel, and the Anchor and Dock properties. So, the new controls are not strictly necessary for you to make full use of the available space but they do give you some new options.
One new object that deserves special mention is FlowDocument. A FlowDocument acts a bit like content on a Web page. It contains text in various styles that flows across the available space. It can also contain objects such as images or even WPF controls that sit on the page as the text flows around them.
WPF provides three controls to display FlowDocuments: FlowDocumentScrollViewer, FlowDocumentPageViewer, and FlowDocumentReader.
- FlowDocumentScrollViewer displays a FlowDocument in one long vertically scrolling sheet?much as a Web browser displays Web pages.
- FlowDocumentPageViewer shows the content one page at a time. It includes built-in zooming and scrolling features to make viewing the entire document easier.
- FlowDocumentReader can display a FlowDocument in one of three ways: like the FlowDocumentScrollViewer does, like the FlowDocumentPageViewer does, or in a mode that displays two pages at a time. The control even provides buttons so users can select a mode. You get all this without having to write a single line of program code.
Figure 6 shows a FlowDocumentReader displaying a FlowDocument in page mode.
|Figure 6. Go With The Flow: A FlowDocument object can hold text, images, shapes, and even WPF controls.|
Styles let you wrap up a collection of property values in a named package so it’s easy to apply the entire set of values to one or more controls. For example, the following XAML snippet defines a style named ButtonStyle that defines font, foreground, background, margin, and width properties for the Button control type.
By defining a style in a window’s resources, you can easily apply that style to a Button. The following XAML element creates a Button control that uses the ButtonStyle style. The Content attribute sets the control’s Content property value (the text it displays) to “Yes.”
Assigning the same style to multiple buttons gives them a common appearance. If you want to change their appearance later, you can simply change the style’s definition in a single place and leave the button definitions alone.
A resource dictionary can hold a collection of styles. You can then apply all the styles to a window at once by setting the window’s resource dictionary appropriately.
For example, the following code makes the window use the resources defined in the separate file NormalResources.xaml.
By changing the Source attribute’s value to a different resource dictionary file, SillyResources.xaml, you can instantly change all the styles used by the window and the controls it contains. This gives you a simple way to implement skinning. Of course, you’ll probably want to do this in code rather than by changing the window’s XAML so the user can choose the skin?but the idea is the same.
Figure 7 shows the same window using two different resource dictionaries. The controls on the window are identical; they just use different styles (property values).
|Figure 7. Snazzy Styling: Styles let you easily set control properties.|
While a style lets you change the appearance of a control by setting property values, a control template lets you change how the control works, by modifying its internal structure. Because changing a control’s internals can involve changing its properties, control templates and styles are sometimes confused.
To make the difference easier to understand, think about the styles used in the previous section. By setting property values for the buttons, the styles change the buttons’ background color, foreground color, size, and even angle of rotation. However, the buttons still behave just as buttons normally do. When the mouse moves over, presses, or releases a button, the button changes appearance accordingly.
Now suppose you wanted to make buttons that have a flat surface with a drop shadow, more rounded corners, and text that extends past the edges. While you cannot use properties or styles to do those things, a control template can do the trick.
The basic idea is for the template to define the controls used by the object (in this case, the button) and to determine how it presents its content.
The following XAML fragment shows a template that redefines how buttons should work.
The ControlTemplate is named OverflowingButton and contains a Grid to hold the button’s content. The Grid contains a Rectangle with rounded corners. The ContentPresenter in the code is the object that holds the button’s text.
The Triggers section indicates how the Button should behave when the mouse is over it. In this example, the code changes the button’s Foreground, FontSize, FontWeight, and BitmapEffect properties whenever the user moves the mouse over the control.
At the end of the example, the Style tag sets a button’s Template property to the OverflowingButton template.
After defining the template and style, your program can simply create buttons and they automatically define themselves according to the template. For example, the following code creates a WrapPanel containing three Buttons.
Figure 8 shows the result. The mouse is hovering over the third button so it is using the properties defined by the template’s triggers.
|Figure 8. Tailor-Made Templates: Templates let you manipulate a control’s inner structure and behavior.|
Note that when you replace a control’s template, you take responsibility for all the control’s structure and behavior. That means you need to implement your own versions of any triggers that you want the control to provide. For this example, that means the Button should really provide some sort of feedback for the properties IsMouseOver, IsPressed, IsFocused, and IsDefaulted (when it’s the window’s default button). It should also change appearance when IsEnabled is false (the control is disabled).
A control template determines the objects that are used internally within a control. A data template determines the objects that display the control’s data.
For example, you can use a data template to make a ListBox display a series of values, each of which contains several sub-values. The template could make the ListBox display the values in a StackPanel containing TextBlocks to hold the sub-values.
Now that you’ve seen some of WPF’s capabilities, here’s a summary of how they provide WPF with some true advantages over Windows Forms:
- Property animations can add a little extra zing to an application.
- Transformations let you move, scale, and rotate elements, making it much easier to build unusual types of interface content, such as vertical or angled labels.
- Multimedia controls make it easier than ever to include audio and video in your applications.
- WPF makes building and manipulating three-dimensional UI objects easier than it is using Direct3D directly.
- Retained-mode graphics make updating and modifying complicated graphics easier.
- Control content can include just about anything, making it much easier to build new combinations such as a Button that contains a Grid that holds other controls.
- New controls give you new layout options.
- The new FlowDocument control lets you build complicated documents containing text, shapes, images, and even WPF controls.
- Styles and templates let you change the appearance, structure, and behavior of controls in a centralized way.
Finally, WPF does have a few disadvantages, the biggest of which is its complexity. Some of WPF’s features are complicated and confusing. Terms and behaviors are sometimes contradictory, with similar code producing different results under different circumstances. The current tools (VS and Expression Blend) are imperfect and provide limited IntelliSense support. (Okay, I admit I’m spoiled by the excellent IntelliSense I get when writing Visual Basic or C# code.) In other words, to really learn WPF you need to overcome a steep learning curve. Finally, there’s cost. The best development environment combines VS (the Express Edition is free) and Expression Blend (which most definitely is not free). You can build WPF applications using only VS, but Blend makes animations a lot easier.
Fortunately, you don’t have to use all the new features to use WPF. If you’re experienced at Windows Forms programming, you can throw the new WPF controls on a Window, add event handlers in the code-behind, and work pretty much as you always have, ignoring property animation, transformations, and three-dimensional graphics. You can add the new tools that you may need now (such as easier multimedia support) and pick up the others if and when you need them.
In later articles, I’ll describe specific pieces of WPF in greater depth. Until then, set up WPF on your computer and start experimenting with the example programs.
WPF is an interesting technology. If you don’t get carried away with animations, multimedia, and other frippery, you can use it to build user interfaces that are truly works of art.