Regardless of which type of WPF application you wish
to build, WPF is ultimately little more than a collection of types
bundled within .NET assemblies. Table 1
describes the core assemblies used to build WPF applications, each of
which must be referenced when creating a new project (as you would hope,
Visual Studio 2010 and Expression Blend WPF projects automatically
reference the required assemblies).
Table 1. Core WPF Assemblies
Assembly | Meaning in Life |
---|
PresentationCore.dll | This
assembly defines numerous types that constitute the foundation of the
WPF GUI layer. For example, this assembly contains support for the WPF
Ink API (for programming against stylus input for Pocket PCs and Tablet
PCs), several animation primitives, and numerous graphical rendering
types. |
PresentationFramework.dll | This assembly contains a majority of the WPF controls, the Application and Window
classes, and support for interactive 2D geometries. As well, this
library provides basic functionality to read and write XAML documents at
runtime. |
System.Xaml.dll | This
assembly provides namespaces which allow you to program against a XAML
document at runtime. By and large, this library is only useful if you
are authoring WPF support tools or need absolute control over XAML at
runtime. |
WindowsBase.dll | This
assembly defines types that constitute the infrastructure of the WPF
API., including those representing WPF threading types, security types,
various type converters, and support for dependency properties and routed events . |
Collectively, these assemblies
define a number of new namespaces and hundreds of new .NET classes,
interfaces, structures, enumerations, and delegates. While you should
consult the .NET Framework 4.0 SDK documentation for complete details, Table 2 describes the role of some (but certainly not all) of the namespaces you should be aware of.
Table 2. Core WPF Namespaces
Namespace | Meaning in Life |
---|
System.Windows | This is the root namespace of WPF. Here you will find core classes (such as Application and Window) that are required by any WPF desktop project. |
System.Windows.Controls | Contains all of the expected WPF widgets, including types to build menu systems, tool tips, and numerous layout managers. |
System.Windows.Data | Types to work with the WPF data binding engine, as well as support for data binding templates. |
System.Windows.Documents | Contains
types to work with the documents API, which allows you to integrate PDF
style functionality into your WPF applications, via the XML Paper
Specification (XPS) protocol. |
System.Windows.Ink | Support
for the Ink API, which allows you to capture input from a stylus or
mouse, respond to input gestures, and so forth. Very useful for Tablet
PC program; however, any WPF can make use of this API. |
System.Windows.Markup | This
namespace defines a number of types that allow XAML markup (and the
equivalent binary format, BAML) to be parsed and processed
programmatically. |
System.Windows.Media | This
is the root namespace to several media-centric namespaces. Within these
namespaces you will find types to work with animations, 3D rendering,
text rendering, and other multimedia primitives. |
System.Windows.Navigation | This
namespace provides types to account for the navigation logicemployed by
XAML browser applications (XBAPs) as well as standard desktop
applications that require a navigational page model. |
System.Windows.Shapes | Defines classes which allow you to render interactive 2D graphics that automatically respond to mouse input. |
To begin your journey into the WPF programming model, you'll examine two members of the System.Windows namespace that are commonplace to any traditional desktop development effort: Application and Window.
NOTE
If you are new to the development of desktop applications using the .NET platform, be aware that the System.Windows.Forms.* and System.Drawing.* assemblies are not related to WPF! These libraries represent the original .NET GUI toolkit, Windows Forms .
1. The Role of the Application Class
The System.Windows.Application class represents a global instance of a running WPF application. This class supplies a Run()
method (to start the application), a series of events that you are able
to handle in order to interact with the application's lifetime (such as
Startup and Exit), and a
number of events that are specific to XAML browser applications (such as
events that fire as a user navigates between pages). Table 3 details some of the key properties to be aware of.
Table 3. Key Properties of the Application Type
Property | Meaning in Life |
---|
Current | This static property allows you to gain access to the running Application object from anywhere in your code. This can be very helpful when a window or dialog box needs to gain access to the Application object that created it, typically to access application wide variables and functionality. |
MainWindow | This property allows you to programmatically get or set the main window of the application. |
Properties | This
property allows you to establish and obtain data that is accessible
throughout all aspects of a WPF application (windows, dialog boxes,
etc.). |
StartupUri | This property gets or sets a URI that specifies a window or page to open automatically when the application starts. |
Windows | This property returns a WindowCollection type, which provides access to each window created from the thread that created the Application
object. This can be very helpful when you wish to iterate over each
open window of an application and alter its state (such as minimizing
all windows). |
1.1. Constructing an Application Class
Any WPF application will need to define a class that extends Application. Within this class, you will define your program's entry point (the Main() method), which creates an instance of this subclass and typically handles the Startup and Exit events. You will build a full example project in just a moment, but here is a quick example:
// Define the global application object
// for this WPF program.
class MyApp : Application
{
[STAThread]
static void Main(string[] args)
{
// Create the application object.
MyApp app = new MyApp();
// Register the Startup / Exit events.
app.Startup += (s, e) => { /* Start up the app */ };
app.Exit += (s, e) => { /* Exit the app */ };
}
}
Within the Startup handler, you will most often process any incoming command line arguments and launch the main window of the program. The Exit
handler, as you would expect, is where you can author any necessary
shut down logic for the program (e.g., save user preferences, write to
the Windows registry).
1.2. Enumerating the Application.Windows collection
Another interesting property exposed by Application is Windows,
which provides access to a collection representing each window loaded
into memory for the current WPF application. Recall that asyou create
new Window objects, they are automatically added into the Application.Windows
collection. Here is an example method that will minimize each window of
the application (perhaps in response to a given keyboard gesture or
menu option triggered by the end user):
static void MinimizeAllWindows()
{
foreach (Window wnd in Application.Current.Windows)
{
wnd.WindowState = WindowState.Minimized;
}
}
You'll build a complete Application-derived type in an upcoming example. Until then, let's check out the core functionality of the Window type and learn about a number of important WPF base classes in the process.
2. The Role of the Window Class
The System.Windows.Window class represents a single window owned by the Application-derived class, including any dialog boxes displayed by the main window. Not surprisingly, Window has a series of parent classes, each of which brings more functionality to the table. Consider Figure 1, which shows the inheritance chain (and implemented interfaces) for System.Windows.Window as seen through the Visual Studio 2010 object browser.
2.1. The Role of System.Windows.Controls.ContentControl
The direct parent of Window is ContentControl,
which is quite possibly the most enticing of all WPF classes. This base
class provides derived types with the ability to host a single piece of
content, which, simply put, refers to the data placed within the interior of the control's surface area via the Content property. The WPF content model makes it very simple to customize the basic look and feel of a content control.
For example, when you think of
a typical "button" control, you tend to assume that the content is a
basic string literal (OK, Cancel, Abort, etc). If you are using XAML to
describe a WPF control, and the value you wish to assign to the Content property can be captured as a simple string, you may set the Content property within the element's opening definition as so (don't fret over the exact markup at this point):
<!-- Setting the Content value in the opening element -->
<Button Height="80" Width="100" Content="OK"/>
NOTE
The Content property can also be set in C# code, which allows you to change the interior of a control at runtime.
However, content can be
anything. For example, let's say you wish to have a "button" that has
something more interesting than a simple string, perhaps a custom
graphic and a blurb of text. In other UI frameworks such as Windows
Forms, you would be required to build a custom control, which could
entail quite a bit of code and a whole new class to maintain. With the
WPF content model, there is no need to do so.
When you wish to assign to the Content property to a value which cannot be captured as a simple array of characters, you are unable to assign the Content property using an attribute in the control's opening definition. Rather, you must define the content data implicitly, within the element's scope. For example, this <Button> contains a <StackPanel> as content, which itself contains some unique data (an <Ellipse> and <Label>, to be exact):
<!-- Implicitly setting the Content property with complex data -->
<Button Height="80" Width="100">
<StackPanel>
<Ellipse Fill="Red" Width="25" Height="25"/>
<Label Content ="OK!"/>
</StackPanel>
</Button>
You can also make use of XAML's property-element syntax to set complex content. Consider the following functionally equivalent <Button> definition, which sets the Content
property explicitly using property-element syntax :
<!-- Setting the Content property using property element syntax -->
<Button Height="80" Width="100">
<Button.Content>
<StackPanel>
<Ellipse Fill="Red" Width="25" Height="25"/>
<Label Content ="OK!"/>
</StackPanel>
<Button.Content>
</Button>
Do be aware that not every WPF control derives from ContentControl,
and therefore not all controls supports this unique content model. As
well, some WPF controls add a few refinements to the basic content model
you have just examined.
2.2. The Role of System.Windows.Controls.Control
Unlike ContentControl, all WPF controls share the Control
base class as a common parent. This base class provides numerous core
members that account for basic UI functionality. For example, Control
defines properties to establish the control's size, opacity, tab order
logic, the display cursor, background color, and so forth. Furthermore,
this parent class provides support for templating services. WPF controls can completely change the way they render their appearance using templates and styles. Table 4 documents some key members of the Control type, grouped by related functionality.
Table 4. Key Members of the Control Type
Members | Meaning in Life |
---|
Background, Foreground, BorderBrush, BorderThickness, Padding, HorizontalContentAlignment, VerticalContentAlignment | These properties allow you to set basic settings regarding how the control will be rendered and positioned. |
FontFamily, FontSize, FontStretch, FontWeight | These properties control various font-centric settings. |
IsTabStop, TabIndex | These properties are used to establish tab order among controls on a window. |
MouseDoubleClick, PreviewMouseDoubleClick | These events handle the act of double-clicking a widget. |
Template | This property allows you to get and set the control's template, which can be used to change the rendering output of the widget. |
2.3. The Role of System.Windows.FrameworkElement
This base class provides a
number of members that are used throughout the WPF framework, such as
support for storyboarding (used within animations) and support for data
binding, as well as the ability to name a member (via the Name property), obtain any resources defined by the derived type, and establish the overall dimensions of the derived type. Table 5 hits the highlights.
Table 5. Key Members of the FrameworkElement Type
Members | Meaning in Life |
---|
ActualHeight, ActualWidth, MaxHeight, MaxWidth, MinHeight, MinWidth, Height, Width | These properties control the size of the derived type. |
ContextMenu | Gets or sets the pop-up menu associated with the derived type. |
Cursor | Gets or sets the mouse cursor associated with the derived type. |
HorizontalAlignment, VerticalAlignment | Gets or sets how the type is positioned within a container (such as a panel or list box). |
Name | Allows to you assign a name to the type, in order to access its functionality in a code file. |
Resources | Provides access to any resources defined by the type . |
ToolTip | Gets or sets the tool tip associated with the derived type. |
2.4. The Role of System.Windows.UIElement
Of all the types within a Window's inheritance chain, the UIElement base class provides the greatest amount of functionality. The key task of UIElement
is to provide the derived type with numerous events to allow the
derived type to receive focus and process input requests. For example,
this class provides numerous events to account for drag-and-drop
operations, mouse movement, keyboard input, and stylus input (for Pocket
PCs and Tablet PCs).
Many of the core events will look quite familiar (MouseMove, KeyUp, MouseDown, MouseEnter, MouseLeave,
etc.). In addition to defining dozens of events, this parent class
provides a number of properties to account for control focus, enabled
state, visibility, and hit testing logic, as shown in Table 6.
Table 6. Key Members of the UIElement Type
Members | Meaning in Life |
---|
Focusable, IsFocused | These properties allow you to set focus on a given derived type. |
IsEnabled | This property allows you to control whether a given derived type is enabled or disabled. |
IsMouseDirectlyOver, IsMouseOver | These properties provide a simple way to perform hit-testing logic. |
IsVisible, Visibility | These properties allow you to work with the visibility setting of a derived type. |
RenderTransform | This property allows you to establish a transformation that will be used to render the derived type. |
2.5. The Role of System.Windows.Media.Visual
The Visual
class type provides core rendering support in WPF, which includes hit
testing of rendered data, coordinate transformation, and bounding box
calculations. In fact, the Visual class interacts with the underlying DirectX subsystem to actually draw data on the screen.WPF provides three possible manners in which you can render graphical
data, each of which differs in terms of functionality and performance.
Use of the Visual type (and its children, such as DrawingVisual)
provides the most lightweight way to render graphical data, but it also
entails the greatest amount of manual code to account for all the
required services.
2.6. The Role of System.Windows.DependencyObject
WPF supports a particular flavor of .NET properties termed dependency properties.
Simply put, this approach allows a type to compute the value of a
property based on the value of other properties. In order for a type to
participate in this new property scheme, it will need to derive from the
DependencyObject base class. In addition, DependencyObject allows derived types to support attached properties,
which are a form of dependency property very useful when programming
against the WPF data-binding model as well as when laying out UI
elements within various WPF panel types.
The DependencyObject base class provides two key methods to all derived types: GetValue() and SetValue().
Using these members, you are able to establish the property itself.
Other bits of infrastructure allow you to "register" who can use the
dependency/attached property in question.
2.7. The Role of System.Windows.Threading.DispatcherObject
The final base class of the Window type is DispatcherObject. This type provides one property of interest, Dispatcher, which returns the associated System.Windows.Threading.Dispatcher object. The Dispatcher
class is the entry point to the event queue of the WPF application, and
it provides the basic constructs for dealing with concurrency and
threading. By and large, this is a lower-level class that can be ignored
by the majority of your WPF applications.