Windows Presentation Foundation

Hello, WPF

WPF from Scratch
Navigation Applications
Content Model
Layout
Controls
Data Binding
Dependency Properties
Resources
Styles and Control Templates
Graphics
Application Deployment
Where Are We?

Layout

Introduction
Layout Basics
DockPanel
StackPanel
Grid
Canvas
Viewbox
Text Layout
Common Layout Properties
When Content Doesn't Fit
Custom Layout
Where Are We?

Controls

Introduction
What Are Controls?
Handling Input
Built-In Controls
Where Are We?

Data Binding

Introduction
Without Data Binding
Data Binding
Binding to List Data
Data Sources
Master-Detail Binding
Where Are We?

Styles and Control Templates

Introduction
Without Styles
Inline Styles
Named Styles
Element-Typed Styles
Data Templates and Styles
Triggers
Control Templates
Where Are We?

Resources

Introduction
Creating and Using Resources
Resources and Styles
Binary Resources
Global Applications
Where Are We?

Graphics

Introduction
Graphics Fundamentals
Shapes
Brushes and Pens
Transformations
Visual-Layer Programming
Video and 3-D
Where Are We?

Animation

Animation Fundamentals
Timelines
Storyboards
Key Frame Animations
Creating Animations Procedurally
Where Are We?

Custom Controls

Introduction
Custom Control Basics
Choosing a Base Class
Custom Functionality
Templates
Default Visuals
Where Are We?

ClickOnce Deployment

A Brief History of Windows Deployment
ClickOnce: Local Install
The Pieces of ClickOnce
Publish Properties
Deploying Updates
ClickOnce: Express Applications
Choosing Local Install versus Express
Signing ClickOnce Applications
Programming for ClickOnce
Security Considerations
Where Are We?

Handling Input

Handling Input

There are three main kinds of user input for a Windows application: mouse, keyboard, and ink.[*] There is also a higher-level concept of a command: a particular action that might be accessible through several different inputs such as keyboard shortcuts, toolbar buttons, and menu items.

[*] Ink is input written with a stylus. You will usually only see this on Tablet PCs and handheld devices.

Although controls typically act as the principal target for input, all elements in a user interface can receive input. This is unsurprising because controls rely entirely on the services of lower-level elements like Rectangle and TextBlock in order to provide visuals. All of the input mechanisms described in the following sections are therefore available on all user-interface element types.

3.2.1. Routed Events

The .NET Framework defines a standard mechanism for exposing events. A class may expose several events, and each event may have any number of subscribers. Although WPF uses this standard mechanism, it augments it to overcome a limitation: if a normal .NET event has no registered handlers, it is effectively ignored.

Consider what this would mean for a typical WPF control. Most controls are made up of multiple visual components. For example, even if you give a button a very plain visual tree consisting of a single Rectangle and provide a simple piece of text as the content, there are still two elements present: the text and the rectangle. The button should respond to a mouse click whether the mouse is over the text or the rectangle. In the standard .NET event-handling model, this would mean registering a MouseLeftButtonUp event handler for both elements.

This problem would get much worse when taking advantage of WPF's content model. A Button is not restricted to having just simple text as a captionit can contain any markup. The example in Figure 3-2 is fairly unambitious, but even this has six elements: the yellow outlined circle, the two dots for the eyes, the curve for the mouth, the text, and the button background itself. Attaching event handlers for every single element would be tedious and inefficient. Fortunately, it's not necessary.

Figure 3-2. A button with nested content


WPF uses routed events, which are more thorough than normal events. Instead of just calling handlers attached to the element that raised the event, a routed event will call all of the handlers attached to any given node, from the originating element right up to the root of the user-interface tree.

Example 3-1 shows markup for the button shown in Figure 3-2. If one of the Ellipse elements inside the Canvas were to receive input, event routing would enable the Button, Grid, Canvas and Ellipse to receive the event, as Figure 3-3 shows.

Example 3-1. Handling events in a user interface tree
<Button MouseLeftButtonDown="MouseButtonDownButton"
        PreviewMouseLeftButtonDown="PreviewMouseButtonDownButton">
    <Grid MouseLeftButtonDown="MouseButtonDownGrid"
            PreviewMouseLeftButtonDown="PreviewMouseButtonDownGrid">
        <Grid.ColumnDefinitions>
            <ColumnDefinition />
            <ColumnDefinition />

        </Grid.ColumnDefinitions>

        <Canvas MouseLeftButtonDown="MouseButtonDownCanvas"
                PreviewMouseLeftButtonDown="PreviewMouseButtonDownCanvas"
                Width="20" Height="18" VerticalAlignment="Center">

            <Ellipse MouseLeftButtonDown="MouseButtonDownEllipse"
                        PreviewMouseLeftButtonDown="PreviewMouseButtonDownEllipse"
                        Canvas.Left="1" Canvas.Top="1" Width="16" Height="16"
                        Fill="Yellow" Stroke="Black" />
            <Ellipse Canvas.Left="4.5" Canvas.Top="5" Width="2.5" Height="3"
                        Fill="Black" />
            <Ellipse Canvas.Left="11" Canvas.Top="5" Width="2.5" Height="3"
                        Fill="Black" />

            <Path Data="M 5,10 A 3,3 0 0 0 13,10" Stroke="Black" />
        </Canvas>

        <TextBlock Grid.Column="1">Foo</TextBlock>
    </Grid>
</Button>


Figure 3-3. Routed events


A routed event can be bubbling , tunneling , or direct . A bubbling event starts by looking for event handlers attached to the element that raised the event, and then looks at its parent, and then its parent's parent, and so on, until it reaches the root of the treethis order is indicated by the numbers on Figure 3-3. A tunneling event works in reverseit looks for handlers at the root of the tree first and works its way down, finishing with the originating element.

Direct events are routed in the same way as normal .NET event handlingonly handlers attached directly to the originating element are notified. This is typically used for events that make sense only in the context of their originating element. For example, it would be unhelpful if mouse enter and leave events were bubbled or tunneledthe parent element is unlikely to care when the mouse moves from one child element to another. At the parent element, you would expect "mouse leave" to mean "the mouse has left the parent element," and because direct event routing is used, that's exactly what it does mean. If bubbling were used, the event would effectively mean "the mouse has left an element that is inside the parent, and is now inside another element that may or may not be inside the parent."

With the exception of direct events , WPF defines most routed events in pairsone bubbling and one tunneling. The tunneling event name always begins with Preview and is raised first. This gives parents of the originating element the chance to see the event before it reaches the child. (Hence the "Preview" prefix.) The tunneling preview event is followed directly by a bubbling event. In most cases, you will only handle the bubbling eventthe preview would usually only be used if you wanted to be able to block the event, or if you needed a parent to do something in advance of normal handling of the event.

In Example 3-1, most of the elements have event handlers that are specified for the MouseLeftButtonDown and PreviewMouseLeftButtonDown eventsthe bubbling and tunneling events respectively. Example 3-2 shows the corresponding code-behind file.

Example 3-2. Handling events
using System;
using System.Windows;
using System.Diagnostics;


namespace EventRouting {
    public partial class Window1 : Window {
        public Window1(  ) {
            InitializeComponent(  );
        }

        private void MouseButtonDownButton(object sender, RoutedEventArgs e)
        { Debug.WriteLine("MouseButtonDownButton"); }

        private void PreviewMouseButtonDownButton(object sender, RoutedEventArgs e)
        { Debug.WriteLine("PreviewMouseButtonDownButton"); }


        private void MouseButtonDownGrid(object sender, RoutedEventArgs e)
        { Debug.WriteLine("MouseButtonDownGrid"); }

        private void PreviewMouseButtonDownGrid(object sender, RoutedEventArgs e)
        { Debug.WriteLine("PreviewMouseButtonDownGrid"); }


        private void MouseButtonDownCanvas(object sender, RoutedEventArgs e)
        { Debug.WriteLine("MouseButtonDownCanvas"); }

        private void PreviewMouseButtonDownCanvas(object sender, RoutedEventArgs e)
        { Debug.WriteLine("PreviewMouseButtonDownCanvas"); }


        private void MouseButtonDownEllipse(object sender, RoutedEventArgs e)
        { Debug.WriteLine("MouseButtonDownEllipse"); }

        private void PreviewMouseButtonDownTextBlock(object sender,
                                                     RoutedEventArgs e)
        { Debug.WriteLine("PreviewMouseButtonDownEllipse"); }

    }
}

Each of the handlers prints out a debug message. Here is the debug output we get when clicking on the TextBlock inside the Canvas:

PreviewButtonDownButton
PreviewButtonDownGrid
PreviewButtonDownCanvas
PreviewButtonDownEllipse
ButtonDownEllipse
ButtonDownCanvas
ButtonDownGrid
ButtonDownButton


This confirms that the Preview event is raised first. It also shows that it starts from the Button element and works down, as we would expect with a tunneling event. The bubbling event that follows starts from the Ellipse element and works up.

This bubbling routing offered for most events means that you can register a single event handler on a control, and it will receive events for any of the elements nested inside of the control. You do not need any special handling to deal with nested content or custom visual tree contentsevents simply bubble up to the control and can all be handled there.

3.2.1.1. Halting event handling

There are some situations in which you might not want events to bubble up. For example, you may wish to convert the event into something elsethe Button element effectively converts MouseLeftButtonDown and MouseLeftButtonUp events into Click events. It suppresses the lower-level events so that only the Click event bubbles up out of the control.

Any handler can prevent further processing of a routed event by setting the Handled property of the RoutedEventArgs, as shown in Example 3-3.

Example 3-3. Halting event routing with Handled
private void ButtonDownCanvas(object sender, RoutedEventArgs e) {
    Debug.WriteLine("ButtonDownCanvas");
    e.Handled = true;
}


Another reason for setting the Handled flag would be if you wanted to prevent normal event handling. If you do this in a Preview handler, not only will the tunneling of the Preview event stop, the corresponding bubbling event that would normally follow will not be raised at all, so it appears as though the event never occurred.

3.2.1.2. Determining the target

Although it is convenient to be able to handle events from a group of elements in a single place, your handler might need to know which element caused the event to be raised. You might think that this is the purpose of the sender parameter of your handler. In fact, the sender always refers to the object to which you attached the event handler. In the case of bubbled and tunneled events, this often isn't the element that caused the event to be raised. In Example 3-1, the ButtonDownWindow handler's sender will always be the Window itself.

Fortunately, it's easy to find out which element was the underlying cause of the event. The RoutedEventArgs object passed as the second parameter offers an OriginalSource property.

3.2.1.3. Routed events and normal events

Normal .NET events (or, as they are sometime called, CLR events ) offer one advantage over routed-event syntax: many .NET languages have built-in support for handling CLR events. Because of this, most routed events are also exposed as CLR events. This provides the best of both worlds: you can use your favorite language's event-handling syntax while taking advantage of the extra functionality offered by routed events.

This is possible thanks to the flexible design of the CLR event mechanism. Although there is a standard simple behavior associated with CLR events, the CLR designers had the foresight to realize that some applications would require more sophisticated behavior. Classes are therefore free to implement events however they like. WPF reaps the benefits of this design by defining CLR events that are implemented internally as routed events.


Example 3-1 and Example 3-2 arranged for the event handlers to be connected by using attributes in the markup. But we could have used the normal C# event-handling syntax to attach handlers in the constructor instead. For example, we could remove the MouseLeftButtonDown and PreviewMouseLeftButtonDown attributes from Example 3-1 and then modify the constructor from Example 3-2 as follows in Example 3-4.

Example 3-4. Attaching event handlers in code
...
public Window1(  ) {
    InitializeComponent(  );

    this.MouseLeftButtonDown += MouseButtonDownWindow;
    this.PreviewMouseLeftButtonDown += PreviewMouseButtonDownWindow;
}
...

We could also do the same for the events from the nested elements. We would just have to apply x:Name attributes in order to be able to access those elements from C#.

The code-behind is usually the best place to attach event handlers. If your user interface has unusual and creative visuals, there's a good chance that the XAML file will effectively be owned by a graphic designer. A designer shouldn't have to know what events a developer needs to handle, or what the handler functions are called. So you will normally get the designer to give elements names in the XAML, and the developer will attach handlers in the code-behind.

3.2.2. Mouse Input

Mouse input is directed to whichever element is directly under the mouse cursor. All user-interface elements derive from the UIElement base class, which defines a number of mouse input events . These are listed in Table 3-1.

Table 3-1. Mouse input events

Event

Routing

Meaning

GotMouseCapture

Bubble

Element captured the mouse.

LostMouseCapture

Bubble

Element lost mouse capture.

MouseEnter

Direct

Mouse pointer moved into element.

MouseLeave

Direct

Mouse pointer moved out of element.

PreviewMouseLeftButtonDown, MouseLeftButtonDown

Tunnel, Bubble

Left mouse button pressed while cursor inside element.

PreviewMouseLeftButtonUp, MouseLeftButtonUp

Tunnel, Bubble

Left mouse button released while cursor inside element.

PreviewMouseRightButtonDown, MouseRightButtonDown

Tunnel, Bubble

Right mouse button pressed while cursor inside element.

PreviewMouseRightButtonUp, MouseRightButtonUp

Tunnel, Bubble

Right mouse button released while cursor inside element.

PreviewMouseMove, MouseMove

Tunnel, Bubble

Mouse cursor moved while cursor inside element.

PreviewMouseWheel, MouseWheel

Tunnel, Bubble

Mouse wheel moved while cursor inside element.

QueryCursor

Bubble

Mouse cursor shape to be determined while cursor inside element.


UIElement also defines a pair of properties that indicate whether the mouse cursor is currently over the element: IsMouseOver and IsMouseDirectlyOver. The distinction between these two properties is that the former will be true if the cursor is over the element in question or over any of its child elements, but the latter will be true only if the cursor is over the element in question but not one of its children.

Note that the basic set of mouse events shown above does not include a click event. This is because clicks are a higher-level concept than basic mouse inputa button can be "clicked" with either the mouse or the keyboard. Moreover, clicking doesn't necessarily correspond directly to a single mouse eventusually, the user has to press and release the mouse button while the mouse is over the control to register as a click. Accordingly, these higher-level events are provided by more specialized element types. The Control class adds a MouseDoubleClick and PreviewMouseDoubleClick event pair. ButtonBase, the base class of Button, CheckBox, and RadioButton, goes on to add a Click event.

If you use a Shape (such as a Rectangle or Path) with a Fill that uses transparency, the shape will act as the target of the input if the mouse is over the shape. This can be slightly surprising if you use a completely transparent brushthe shape will not be visible, but it will still be the input target, regardless of what the mouse may appear to be over. If you want a shape with a transparent fill that does not capture mouse input, simply supply no Fill at allif the Fill is null, (as opposed to being a completely transparent brush), the shape will not act as an input target.!


Remember that if the reason you are considering handling a mouse event is simply to provide some visible feedback to the user, writing an event handler may be overkill. It is often possible to achieve the visible effects you require entirely within the markup for a style by using declarative property triggers and event triggers. (Triggers are discussed in Chapter 5.)

3.2.3. Keyboard Input

Keyboard input introduces the idea of focus. Unlike the mouse, there is no way for the user to move the keyboard over an element in order to indicate the target for input. In Windows, a particular element is designated as having the focus, meaning that it acts as the target for keyboard input. The user sets the focus by clicking the mouse or tapping the stylus on the control in question, or by using navigation keys such as the Tab and cursor keys.

In principle, any user interface element can receive the focusthe IsFocused property is defined on UIElement, the base class of FrameworkElement. However, the Focusable property determines whether this feature is enabled on any particular element. By default, this is true for controls and false for other elements.


Table 3-2 shows the keyboard input events offered on user-interface elements. All of these items use tunnel and bubble routing for the Preview and main events, respectively.

Table 3-2. Keyboard input events

Event

Routing

Meaning

PreviewGotFocus, GotFocus

Tunnel, Bubble

Element received the focus.

PreviewLostFocus, LostFocus

Tunnel, Bubble

Element lost the focus.

PreviewKeyDown, KeyDown

Tunnel, Bubble

Key pressed.

PreviewKeyUp, KeyUp

Tunnel, Bubble

Key released.

PreviewTextInput, TextInput

Tunnel, Bubble

Element received text input.


Note that TextInput is not necessarily keyboard input. It represents textual input in a device-independent way, so this event can also be raised as a result of ink input.

3.2.4. Ink Input

The stylus used on tablet PCs and other ink-enabled systems has its own set of events. Table 3-3 shows the ink input events offered on user-interface elements.

Table 3-3. Stylus and ink events

Event

Routing

Meaning

GotStylusCapture

Bubble

Element captured stylus.

LostStylusCapture

Bubble

Element lost stylus capture.

PreviewStylusDown, StylusDown

Tunnel, Bubble

Stylus touched screen over element.

PreviewStylusUp, StylusUp

Tunnel, Bubble

Stylus left screen while over element.

PreviewStylusEnter, StylusEnter

Tunnel, Bubble

Stylus moved into element.

PreviewStylusLeave, StylusLeave

Tunnel, Bubble

Stylus left element.

PreviewStylusInRange, StylusInRange

Tunnel, Bubble

Stylus moved close enough to screen to be detected.

PreviewStylusOutOfRange, StylusOutOfRange

Tunnel, Bubble

Stylus moved out of detection range.

PreviewStylusMove, StylusMove

Tunnel, Bubble

Stylus moved while over element.

PreviewStylusInAirMove, StylusInAirMove

Tunnel, Bubble

Stylus moved while over element but not in contact with screen.

PreviewStylusSystemGesture, StylusSystemGesture

Tunnel, Bubble

Stylus performed a gesture.

PreviewTextInput, TextInput

Tunnel, Bubble

Element received text input.


3.2.5. Commands

Many applications provide more than one way of performing certain actions. For example, consider the act of creating a new file. You might choose the File New menu item, or you could click the corresponding toolbar button. Alternatively, you might use a keyboard shortcut such as Ctrl+N. If the application provides a scripting system, a script could provide yet another way to perform the action. The outcome is the same whichever mechanism you use, because these are all just different ways of invoking the same underlying command.

WPF has built-in support for this idea. The RoutedCommand class represents a logical action that could be invoked in several ways. In a typical WPF application, each menu item and toolbar button is associated with an underlying RoutedCommand object.

RoutedCommand works in a very similar way to lower-level forms of input. When a command is invoked, it raises two events: PreviewExecuteEvent and ExecuteEvent. These tunnel and bubble through the element tree in the same way as input events. The target of the command is determined by the way in which the command was invoked. Typically, the target will be whichever element currently has the focus, but RoutedCommand also provides an overloaded Execute method, which may be passed a specific target element.

There are several places from which you can get hold of a RoutedCommand. A few controls offer commands. For example, the ScrollBar control defines commands for each of its actions and makes these available in static fields, such as LineUpCommand and PageDownCommand . However, most commands are not unique to a particular control. Some correspond to application-level actions such as "new file" or "open." Others represent actions that would be invoked on a control, but could be implemented by several different controls. For example, both TextBox and RichTextBox can handle clipboard operations.

There is a set of classes that provide standard commands. These classes are shown in Table 3-4. This means you don't need to create your own RoutedCommand objects to represent the most common operations. Moreover, many of these commands are understood by built-in controls. For example, TextBox and RichTextBox support many of these standard operations, including clipboard, undo, and redo commands.

Table 3-4. Standard command classes

Class

Command types

ApplicationCommands

Commands common to almost all applications. Includes clipboard commands, undo and redo, and document-level operations (open, close, print, etc.).

ComponentCommands

Operations for moving through information such as scroll up and down, move to end, and text selection.

EditCommands

Text-editing commands such as bold, italic, and alignment.

MediaCommands

Media-playing operations such as transport (play, pause, etc.), volume control, and track selection.


3.2.5.1. Handling commands

For a command to be of any use, something must respond to it. This works slightly differently from handling normal input events, because most commands are not defined by the controls that will handle them. The classes in Table 3-4 define 95 commands, so if Control defined CLR events for each distinct command, that would require 190 events once you include previews. Not only would this be extremely unwieldy, it wouldn't even be a complete solutionmost applications define their own custom commands as well as using standard ones. The obvious alternative would be for the RoutedCommand itself to raise events. However, each command is a singletonthere is only one ApplicationCommands.New object, for example. If you were able to add a handler to a command object directly, that handler would run any time the command was invoked anywhere in your application. What if you just want to handle the command when it is executed in a particular window?

The CommandBinding class solves these problems. A CommandBinding object maps a specific RoutedCommand onto a handler function in the scope of a particular user-interface element. It is this CommandBinding that raises the PreviewExecute and Execute events, rather than the UI element. These bindings are held in the CommandBindings property defined by UIElement. Example 3-5 shows how to handle the ApplicationCommands.New command in the code-behind file for a window.

Example 3-5. Handling a command
public partial class Window1 : Window {
    public Window1(  ) {
        InitializeComponent(  );

        CommandBinding cmdBindingNew = new CommandBinding(ApplicationCommands.New);
        cmdBindingNew.Execute +=  NewCommandHandler;
        CommandBindings.Add(cmdBindingNew);
    }

    private void NewCommandHandler(object sender, ExecuteEventArgs e) {
        if (unsavedChanges) {
            MessageBoxResult result = MessageBox.Show(this,
                "Save changes to existing document?", "New",
                MessageBoxButton.YesNoCancel);

            if (result == MessageBoxResult.Cancel) {
                return;
            }
            if (result == MessageBoxResult.Yes) {
                SaveChanges(  );
            }
        }

        // Reset text box contents
        inputBox.Clear(  );
    }
}

This code relies on the bubbling nature of command routingthe top-level Window element is unlikely to be the target of the command, as the focus will usually belong to some child element inside the window. However, the command will bubble up to the top. This routing makes it easy to put the handling for commands in just one place.

The command that Example 3-5 handles is ApplicationCommands.New. If the set of standard commands does not meet all of your application's needs, you can define custom commands for specialized operations.

3.2.5.2. Defining commands

Example 3-6 shows how to define a command. WPF uses object instances to establish the identity of commands. If you were to create a second command of the same name, it would not be treated as the same command. For this reason, commands are usually put in static fields or properties.

Example 3-6. Creating a custom command
public partial class Window1 : Window {
    public static RoutedCommand FooCommand;

    static Window1(  ) {
        InputGestureCollection fooInputs = new InputGestureCollection(  );
        fooInputs.Add(new KeyGesture 
(Key.F,
                                     ModifierKeys.Control|ModifierKeys.Shift));
        FooCommand = new RoutedCommand("Foo", typeof(Window1), fooInputs);
    }
    ...
}


The Foo command created in Example 3-6 would be handled using a CommandBinding just like any other command. Of course, the user needs some way of invoking the command.

3.2.5.3. Invoking commands

As well as defining a custom command, Example 3-6 also shows one way in which a command can be associated with user input. This particular command has been configured to be invoked by a specific input gesture . Two input-gesture types are currently supported: a MouseGesture is a particular shape made with the mouse or stylus; a KeyGesture, as used in Example 3-6, is a particular keyboard shortcut. Many of the built-in commands are associated with standard gestures. For example, ApplicationCommands.Copy is associated with the standard keyboard shortcut for copying. (Ctrl+C in most locales.)

Although a command can be associated with a set of gestures when it is created, you may wish to assign additional shortcuts for the command in the context of a particular window. To allow this, user-interface elements have an InputBindings property. This collection contains InputBinding objects, which associate input gestures with commands. These augment the default gestures associated with the command.

Input gestures such as keyboard shortcuts are not the only way in which commands can be invoked. You can call the Execute method on the command in order to invoke it from code. As Example 3-7 shows, Execute is overloaded. If you pass no parameters, the command target will be whichever element has the focus, just as it would be if the command had been invoked using an input gesture. But you can pass in a target element if you want.

Example 3-7. Invoking a command from code
ApplicationCommands.New.Execute(  );
...or...
ApplicationCommands.New.Execute(targetElement);

You might think that you would write code like this in click handlers for menu items or toolbar buttons. However, since commands are so often associated with menu items or buttons on a toolbar, Button and MenuItem both offer a Command property. This identifies the command to invoke when the element is clicked. This provides a declarative way of connecting user-interface elements to commands. You only need to write an event handler for the command itself, rather than a handler for each UI element bound to the command. Example 3-8 shows a Button associated with the standard Copy command.

Example 3-8. Invoking a command with a Button
<Button Command="Copy">Copy</Button>

Because this example uses a standard command from the ApplicationCommands class, we can use this short-form syntax, specifying nothing but the command name. For commands not defined by the classes in Table 3-4, a little more information is required. The full syntax for a command attribute in XAML is:

[[xmlNamespacePrefix:]ClassName.]EventName

If only the event name is present, the event is presumed to be one of the standard ones. For example, Undo is shorthand for ApplicationCommands.Undo. Otherwise, you must also supply a class name, and possibly a namespace prefix. The namespace prefix is required if you are using either custom commands or commands defined by some third-party component. This is used in conjunction with the Mapping XML processing instruction used to make external types available in a XAML file. (See Appendix A for more information on the Mapping processing instruction.)

Example 3-9 shows the use of the command-name syntax with all the parts present. The value of m:MyCommands.Foo means that the command in question is defined in the MyLib.Commands.MyCommands class in the mylib component and is stored in either a field or a property called Foo.

Example 3-9. Using a custom command in XAML
<?Mapping ClrNamespace="MyLib.Commands" Assembly="mylib"
          XmlNamespace="urn:mylib" ?>

<Window xmlns:m="urn:mylib" ...>
    ...
    <Button Command="m:MyCommands.Foo">Custom Command</Button>
    ...


3.2.5.4. Enabling commands

As well as being executable, commands also offer a QueryEnabled method. This returns a Boolean indicating whether the command can be invoked right now; certain commands are only valid in particular contexts. This feature can be used to determine whether items in a menu or toolbar should be grayed out. Calls to the QueryEnabled method are handled in much the same way as calls to Execute; CommandBinding objects are used to handle the query. The binding raises a PreviewQueryEnabled and QueryEnabled pair of events, which tunnel and bubble in the same way as the PreviewExecute and Execute events. Example 3-10 shows how to handle this event for the system-defined Redo command.

Example 3-10. Handling QueryEnabled
public Window1(  ) {
    InitializeComponent(  );

    CommandBinding redoCommandBinding =
            new CommandBinding(ApplicationCommands.Redo);
    redoCommandBinding.QueryEnabled += RedoCommandQueryEnabled;
    CommandBindings.Add(redoCommandBinding);
}

void RedoCommandQueryEnabled(object sender, QueryEnabledEventArgs e) {
    if (!CanRedo(  )) {
        e.IsEnabled = false;
    }
}

Unfortunately, the current build of WPF at the time of writing does not gray out menu or toolbar items. It raises the QueryEnabled event when a menu item is invoked and prevents the command from executing if it is disabled, but does not currently provide any visual indication that a menu item is disabled. We hope this will be addressed in a future release.


We've seen all of the various ways in which controls handle input in WPF. Now let's look at the set of controls built into WPF.


©2008 FAQ - WPF Labs - Discuss - Terms of Use - Privacy Policy - About WPF
- Interview Questions - Sharepoint Articles - Interview Questions Resource Library - All about LINQ - MS Knowledgebase Articles - Electronics and Hardware discussions