Appendix. Base Services

Syncategorematic: Syn*cat`e*gor`e*mat"ic … Not capable of being used as a term by itself;—said of words, as an adverb or preposition.
Source: Webster’s Revised Unabridged Dictionary, © 1996, 1998 MICRA, Inc.

WINDOWS PRESENTATION FOUNDATION provides a very rich and deep set of services. The goal of this book was to cover the major concepts of the platform in the previous eight chapters. There is, however, a set of services that are often useful and may help us understand how the system is built and hangs together. This appendix reviews some of my favorite WPF services and describes how they might be used in an application.

Threading and Dispatchers

At the outset, one of the WPF development team’s goals was to remove the antiquated dependency on the single-threaded apartment (STA) model of threading. Many ActiveX controls and other COM-based services require the STA threading model, which states that only one thread at a time will ever be executing against our code, and it will always be the same thread. For any Windows UI programming today, the code is almost always running in an STA model.

The problem with STA is that all objects are tied to a single thread and can’t move between threads. Enforcing a single thread of execution in a given body of code is a very effective simplification, but tying execution to a specific instance of a thread seems too limiting. Alas, as “Longhorn” became Vista, we came to the realization that, for WPF to work together with almost any existing service (Clipboard, Internet Explorer, etc.), we would have to support STA, so we decided to create a single threading model instead of supporting many threading models.

So it is with great apology that I report that WPF requires STA threading. The first place we run into this requirement is when we write a typical Hello World application; it has the STAThread attribute on the entry point function:

Image

Most WPF objects derive from a common base type: DispatcherObject. Partly because of the original intent to move away from STA, we tie objects not to the thread, but to a single dispatcher. A dispatcher is an object that receives messages (events in the CLR world, messages in the User32 world) and dispatches them to the correct object. Most of the types related to the dispatcher and WPF’s threading model are located in the System.Windows.Threading namespace.

True shared memory concurrency (multithreading) is almost impossible to program correctly with today’s mainstream programming languages. The problem has to do with the complex rules of locking and concurrency management: If we don’t lock correctly, we quickly run into race conditions, deadlocks, livelocks, and memory corruption. The most successful model for doing more than one thing at a time is to have a loose coupling between the two tasks and use an asynchronous messaging model for communicating between the two threads.

One of the changes to the threading support that shipped in the .NET Framework 2.0 was the introduction of SynchronizationContext. This class lets a platform, like WPF, tell the system how to deal with concurrency management. In the case of WPF, it pushes a reference to the dispatcher into the context, so any asynchronous callbacks from components (like System.Net.WebClient) can be posted back to the UI thread. This happens automatically, so we can ignore any threading issues.

To see this in action, let’s write a simple program that downloads an HTML page from a Web site. The simplest way to write this program is to use the WebClient class and call DownloadStringAsync:

Image

Running this program just works, as Figure A.1 illustrates. What happens is that the WebClient type retrieves SynchronizationContext, which it then uses to post events (an action that results in the callback delegates being invoked on the UI thread). This model works well for doing asynchronous programming without introducing the complexity of multithreading.

Figure A.1. Downloading some HTML content asynchronously

image

Sometimes we really do want to do explicit multithreading—for example, to create a background thread for a long-running process. In such cases we have two ways to handle communication with the UI thread. If we’re creating a reusable component that may be used outside of a WPF application (as in a Windows Forms or ASP.NET application), then we should manage the callbacks using SynchronizationContext just as WebClient does. If, instead, we’re implementing application logic that is tied to a program, we can directly use the dispatcher associated with the UI thread. By talking to the dispatcher directly, we gain more control over how the messages are processed, but we no longer post callbacks to the correct context in Windows Forms or ASP.NET.

Regardless of the style of component we build, the pieces are the same. We need to create an object to represent a task and an object to represent the result “message.” Here we’ll create a task that calculates the sum of numbers from 0 to (n – 1). The result message will be an EventArgs-derived type that contains the result value:

Image

The task object needs only a simple object model, which should follow the asychronous component pattern. We will have a <DoSomething>  Async method and a <DoSomething>Completed event:

Image

In this case we’ll use SynchronizationContext to manage the callbacks, so in our constructor we will capture the current context:

Image

To make this task run on a background thread we will need to define two functions. The first is the implementation of the background thread execution, which we will call BackgroundTask. The second function is the callback that will happen on the UI thread, which we will call Completed. Notice that we don’t touch any state on the object from the background thread, thereby ensuring that there are no conflicts. To avoid subtle threading bugs, all the data will be accessed only from the UI thread. We must copy any data we need into the arguments that we pass to the background thread:

Image

This type works exactly like the WebClient type. We create it, hook up a listener to the event, and then call SumAsync:

Image

The primary benefit of using the WPF dispatcher instead of SynchronizationContext is the ability to express the priority of the callback to the UI thread. The System.Windows.Threading.DispatcherPriority enum defines the 12 priorities that we can associate with a callback to the UI thread. It is simpler, though, to use the BackgroundWorker component that is included in .NET, which leverages SynchronizationContext.

Properties

When designing types, we often talk about their PMEs: properties, methods, and events. These three concepts define the developer’s view of an object. The previous big component model from Microsoft, COM, really supported only methods. Properties were barely supported, with a bit of metadata in the interface definition to tag put_ and get_ methods so that tools like VB could present a property-based model; events were implemented straight out instead of with makeshift callback sinks.

One of the design goals for .NET was to natively support these concepts. Events and properties were given special billing in both the runtime and almost all the major languages targeting .NET. WPF is built from the ground up in managed code. The WPF team made the decision early on to follow .NET conventions and patterns, and use native features of the runtime. So why on earth is there a WPF property system?

.NET Properties

While we are here at the base of the WPF system, looking at the lowest-level services, it is interesting to think about what we’re going to build on top. We want to build a dynamic, data-driven, declarative, composited presentation system.

Let’s start with the beginning—a CLR property on a fictitious type:

Image

We have defined two properties: Background and Parent. The first challenge we hit is that, when Background changes, we want to cause Widget to repaint. Of course, other developers may want to know that the background changed, so we will make the change notification public:

Image

Simple! The next thing we probably want is the ability to have the background match the parent:

Image

We aren’t quite out of the woods yet. We have missed two critical things: First, when the parent changes and the background isn’t set, we need to fire the change notification. Second, we need to provide a mechanism for resetting the background to its default (inherited) value:

Image

Here we already begin to see a lot of duplicate code. Remember, though, that a key part of the dynamic, data-driven, declarative system is the notion of styling. To facilitate better code reuse, WPF enables a single object to be defined that can apply property values to multiple other objects; this capability is comparable to the use of styles inside of Microsoft Word or CSS styles in HTML. Of course, we want our widget to support this functionality:

Image

In this example we have added a lot more boilerplate code for the Style property, and some interesting code inside of the get method for Background. We have many more features to add to properties (animation, default values, etc.) to match all the functionality that WPF will require, but before we get too far, let’s look at the design that we’re producing.

To start, any inherited property must be defined on the base type. Because we have a hard-coded lookup from a given widget to its parent, at compile time of the base type we have to know every property that may need to be inherited. The same is true for styles: Because the definition for Style needs to be updated for each property, the only properties that can be styled are the ones we know about in advance. We are duplicating a lot of code for change notifications. We had to hard-code the dependencies between properties; specifically, we had to write code in the parent change notification to fire the background change notification. We had to allocate a local field on the type for every property. The list goes on.

Property System 101

Boiling all this down, the WPF team pinpointed three essential services in a property system:

  1. Change notification
  2. Dependency tracking
  3. Expressions

Initially these may not seem like enough, but the logic works something like this: If we have the ability to know when a property changes, and we understand the properties affected by that change, we can then implement complex expressions that enable many features (inheritance, styles, etc.). Using these three concepts, we can model all the other services in the property system; the only one that’s not documented anywhere is expressions. Expressions are an internal-only concept in the first version of WPF. Instead, WPF exposes a richer set of built-in functionality:

  1. Sparse storage
  2. Styling
  3. Animation
  4. Binding
  5. Attached properties

To facilitate all this is a base class that encapsulates this behavior in a generic way:

Image

There are basically three functions (get, set, and clear), and a callback (change notification). DependencyProperty is an object that represents the identity of the property; it is the programmatic name of the property.

DependencyObject provides sparse storage. This is important: Properties defined using the property system incur no cost per instance unless they are set to something other than a default value. Sparse storage was a big goal in defining the property system because we knew that the framework would heavily utilize properties (there are more than 40 just to control text rendering!), and any per-instance cost would destroy performance. The source for DependencyObject looks something like this:

Image

The logic is more complex than this, but this simplified version shows that there is now a fixed overhead per object of a dictionary, and we can have any number of properties. This flexibility doesn’t come without a cost; if most of the properties are set locally (instead of with a style, inheritance, or default value), we’ll have worse performance than if we used only local values.

Converting our widget code over to using the property system is trivial:

Image

However, it would be rude (and break most tools!) if we left it at this. Remember that WPF had a premise to follow .NET conventions, and that includes using the property system built into .NET. The dependency property system is designed to be an addition to the .NET system, not a replacement:

Image

Metadata

.NET already has a notion of metadata: We can declare a custom attribute on any member, type, or assembly. The system has limitations, one of which is performance. For the dependency property system it was absolutely critical to enable high-performance operations and discovery of certain aspects of the property, which is one reason why declaring a dependency property requires telling the property system what the type of the property is (so that we don’t have to reflect against the type and find the CLR wrapper to find the property type).

The dependency property system stores metadata in two ways. First, a set of information is stored on the dependency property itself. This information includes the name and type of the property, as well as the type that declared the property (the owner). Property names must be unique for each owner type.

The second store for metadata in the dependency property system is the PropertyMetadata object. Although the information in Dependency  Property is fixed, we are free to define new properties on our own derived type of PropertyMetadata. PropertyMetadata allows us to control additional behavioral metadata (DefaultValue and IsReadOnly), globally listen to change notifications (PropertyChangedCallback), and apply value coercion (CoerceValueCallback).

DefaultValue determines what value should be returned when the property isn’t set. Most properties should specify such a default. The norm is to return the default value for the given data type (null for any reference type, 0 for numerics, false for booleans, etc.). IsReadOnly, as the name implies, forces the property to be read-only. In .NET, read-only fields are enforced at a low level by the intermediate-language verifier, ensuring that all read-only fields are assigned exactly once by the time the constructor is run. In the dependency property system, the guarantee around read-only is looser, ensuring only that the owning type (or an instance of that owning type) assigns to the property.

Global change notification for a property is pretty simple to understand, but the value coercion is worth looking at a bit more in depth. The simplest way to understand value coercion is to think about the Slider control. Slider supports three properties: Minimum, Maximum, and Value. The design requires that Value return a value between Minimum and Maximum, but we also know that properties may be set in any order. To make sure that no values violate the minimum and maximum constraints, while allowing the flexibility of setting properties in any order desired, we want to support storing any value in the Value property but constrain that value between Minimum and Maximum when we get the value.

The first step to leveraging value coercion is to define our properties:

Image

Because we always want Value to be bounded by Minimum and Maximum, we will introduce a new static method that performs the coercion and add it to the metadata for Value:

Image

Here’s where it gets a little tricky. One main advantage of the property system is that it attempts to understand all dependencies between properties to efficiently cache values and communicate changes. This coercion has introduced a new dependency. Because there is no general extensibility mechanism for adding dependencies, instead we need to manually drive the property system to deal with change notifications. We can add a global property change handler for Maximum and Minimum, and invalidate the Value property whenever either changes:

Image

Beyond the basic PropertyMetadata type, there is an important derived type, FrameworkPropertyMetadata, that allows customization of a property’s behavior with respect to the higher-level features of WPF, such as binding, styles, and inheritance.

Keyboards, Mice, and Styluses

Back in the early days of User32, the general model for handling special keys (like Ctrl+S for save) was either to use an accelerator table[1] or to handle WM_KEYDOWN and WM_KEYUP. In Visual Basic it was common to handle KeyDown/KeyUp events because there was no way to build a custom accelerator table. There are two big problems with doing anything in direct response to keyboard input: First, sytems with input method editors (Japanese, Korean, Chinese, etc.) tend to break; and second, the ability to let the user rebind the keystrokes to other behavior is lost.

In some scenarios we do need to talk to a device directly—listening to the stylus in a paint program, for example—but in most cases we want to bind to commands. The binding from input events to commands is fairly powerful by default, but it is completely extensible, such that we can implement our own rules for when to raise a command.

By structuring an application with input bindings as a separate concept, we can easily allow end users to customize bindings to suit their needs. In Chapter 7 we touched briefly on input bindings, but let’s take a closer look.

InputBinding

InputBinding has two interesting properties: Gesture and Command. Gesture maps to any input gesture that we want to map to a given command. Both InputGesture (the data type of the Gesture property) and ICommand (the data type of the Command property) are extensible, allowing us to map any gesture to any command. By default, WPF supports two types of gestures: key and mouse gestures. These allow the common set of accelerators and behaviors needed to build basic applications.

A more advanced type of gesture is something we commonly see in development tools: key chords. Key chords consist of a set of key inputs that are uninterrupted, allowing for combinations of keys to have special meanings (e.g., in Emacs, the binding to Ctrl+X, S to mean “save”). To show the extensibility of the binding system, let’s add support to WPF for binding to key chords.

The gesture we want to support is really a collection of key gestures. The built-in KeyGesture type in WPF doesn’t support keys without any modifier presses (control, shift, etc.), but in a key-chord scenario, it is common for the second key to be neutral. The first step is to define a new KeyChordItemGesture object, which will map to one “note” in the key chord. InputGesture has only one important method, Match, which determines whether a given gesture maps to an input event:

Image

We can now create the KeyChordGesture type, which contains a collection of input gestures that must be matched in order. A queue of gestures to match is maintained, and as each gesture is matched it is removed. If the user presses an incorrect key, the queue is drained:

Image

The final step is to define an input binding. We have no custom object model to add to our binding, but the base InputBinding type has no public constructor, so we need to define a type simply to make it usable in markup:

Image

This binding can now be used on any control in the InputBindings collection:

Image

By defining custom binding types, we can avoid ever having hard-coded dependencies between logic (command handlers) and user input. Avoiding such dependencies is valuable in making an application configurable, and in making sure that we can work against any type of input.

WPF’s philosophy is to move to more declarative programming of input devices, so features like input bindings are made to be much closer to the surface, and talking to the devices themselves is somewhat obscured. If we do need to talk to the input devices, WPF has a rich object model.

Input Device Communication

The object models for all input devices are structured in the same way. There is one static service class (Keyboard, Mouse, Stylus, or Tablet) and a device class (KeyboardDevice, MouseDevice, etc.). The static service class provides global functionality (like attaching to direct input events and retrieving the devices), and the device classes provide device-specific functionality. The most common properties for the primary instance of a given device are generally promoted to the static service class.

To firm up this concept of communication, let’s consider the keyboard. In the earlier KeyChordItemGesture implementation, you may have noticed that we retrieved the current state of the modifier keys by looking at the Keyboard class:

Image

Keyboard.Modifiers is a static property that is implemented as a call to Keyboard.PrimaryDevice.Modifiers. The system allows only one keyboard and only one mouse. For stylus input, however, multiple tablets (digitizers) may be attached to the system, and each tablet may have one or more styluses associated with it. Tablet.TabletDevices will return the enumeration of all the tablets currently recognized by the system.

With mouse and stylus input, the location of the mouse or stylus determines the target, or focused, control. Using Capture, we can lock the device to a specific control for a period of time, but generally the focus simply travels along with the pointer. Keyboard focus is a different story.

Keyboard Focus

Only one control can have keyboard focus at a time. There are two interesting types for dealing with focus: KeyboardNavigation and FocusManager. KeyboardNavigation is responsible for dealing with how keyboard focus will move around elements when various keys are pressed, and the FocusManager is responsible for tracking the keyboard focus. FocusManager can largely be ignored because all the interesting events and properties that it exposes are available in more convenient places (like Keyboard and UIElement).

KeyboardNavigation, on the other hand, provides a way for controls to determine how they want to deal with keyboard focus commands. Probably the most commonly used properties are IsTabStop and TabIndex. The most common way for users to move the keyboard focus around a set of controls (besides using the mouse) is by using the Tab key. The Tab key is designed to move the keyboard focus to the next logical element into which the user can type.

Where Are We?

In this appendix we have looked at a few of the base services provided by WPF. Although typically you won’t have to interact with these services directly, it is often useful to understand some of them so that you know better what is available to build on.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset