RSS Feed
Download our iPhone app
Browse DevX
Sign up for e-mail newsletters from DevX


WPF Wonders: Getting Started with WPF : Page 4

Learn how to use Windows Presentation Foundation to build engaging, dynamic user interfaces that can really grab the user's attention.

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.

   <Style x:Key="ButtonStyle" TargetType="{x:Type Button}">
       <Setter Property="FontSize" Value="12" />
       <Setter Property="FontWeight" Value="Bold" />
       <Setter Property="Foreground" Value="Blue" />
       <Setter Property="Background" Value="LightBlue" />
       <Setter Property="Margin" Value="5" />
       <Setter Property="Width" Value="75" />
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."

   <Button Style="{DynamicResource ButtonStyle}" Content="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.

               <ResourceDictionary Source="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.
Control Templates
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.

   <ControlTemplate x:Key="OverflowingButton" TargetType="Button">
       <Grid Name="ButtonGrid">
           <Rectangle RadiusX="10" RadiusY="10"
               Fill="LightBlue" Margin="5" />
               VerticalAlignment="Center" />
               <DropShadowBitmapEffect />
           <Trigger Property="IsMouseOver" Value="True">
               <Setter Property="Foreground" Value="#FFFF0000" />
               <Setter Property="FontSize" Value="14"/>
               <Setter Property="FontWeight" Value="Bold"/>
               <Setter Property="BitmapEffect">
                       <DropShadowBitmapEffect />
   <Style TargetType="Button">
       <Setter Property="Template"
           Value="{StaticResource OverflowingButton}" />
       <Setter Property="FontSize" Value="12"/>
       <Setter Property="Margin" Value="20"/>
       <Setter Property="MinWidth" Value="50" />
       <Setter Property="MinHeight" Value="50" />
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.

       <Button Content="Write Code" />
       <Button Content="Debug Code" />
       <Button Content="Update Resume" />
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).

Data Templates
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.

Close Icon
Thanks for your registration, follow us on our social networks to keep up-to-date