Keyboard and Ink Input with WPF

In this third part of a five-part series that walks you through the input handling mechanisms available in WPF, you will learn about keyboard and printer-related input. We will also start talking about commands. This article is excerpted from Programming WPF, Second Edition, written by Chris Sells and Ian Griffiths (O'Reilly, 2007; ISBN: 0596510373). Copyright © 2007 O'Reilly Media, Inc. All rights reserved. Used with permission from the publisher. Available from booksellers or direct from O'Reilly Media.

Contributed by
Rating: 5 stars5 stars5 stars5 stars5 stars / 3
July 10, 2008
Rate this Article:
MEH MEH++


SEARCH ASP FREE
TOOLS YOU CAN USE

advertisement

Keyboard Input

The target for mouse input is always the element currently under the mouse, or the element that has currently captured the mouse. This doesn’t work so well for keyboard input—the user cannot move the keyboard, and it would be inconvenient to need to keep the mouse directly over a text field while typing. Windows therefore uses a different mechanism for directing keyboard input. At any given moment, 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 control in question with the mouse or stylus, or by using navigation keys such as the Tab and arrow keys.

TheUIElementbase class defines anIsFocusedproperty, so in principle, any user interface element can receive the focus. However, theFocusableproperty determines whether this feature is enabled on any particular element. By default, this is true for controls, and false for other elements.

Table 4-2 shows the keyboard input events offered by user interface elements. Most of these items use tunnel and bubble routing for the preview and main events, respectively.

Table 4-2. Keyboard input events

Event

Routing

Meaning

PreviewGotKeyboardFocus, GotKeyboardFocus

Tunnel, Bubble

Element received the keyboard focus.

PreviewLostKeyboardFocus, LostKeyboardFocus

Tunnel, Bubble

Element lost the keyboard focus.

GotFocus

Bubble

Element received the logical focus.

LostFocus

Bubble

Element lost the logical focus.

PreviewKeyDown, KeyDown

Tunnel, Bubble

Key pressed.

PreviewKeyUp, KeyUp

Tunnel, Bubble

Key released.

PreviewTextInput, TextInput

Tunnel, Bubble

Element received text input.

Strictly speaking, theTextInputevent is not caused exclusively by keyboard input. It represents textual input in a device-independent way, so this event can also be raised as a result of ink input from a stylus.

As Table 4-2 shows, WPF makes a distinction between logical focus and keyboard focus. Only one element can have the keyboard focus at any given instant. Often, the focus will not even be in your application—the user may switch to another application. However, applications typically remember where the focus was so that if the user switches back, the focus returns to the same place as before. WPF defines the logical focus concept to keep track of this: when an application loses the keyboard focus, the last element that had the keyboard focus retains the logical focus. When the application regains the keyboard focus, WPF ensures that the focus is put back into the element with the logical focus.

Keyboard State

The Keyboard class provides a static property called Modifiers. You can read this at any time to find out which modifier keys, such as the Alt, Shift, and Ctrl keys, are pressed. Example 4-12 shows how you might use this in code that needs to decide whether to copy or move an item according to whether the Ctrl key is pressed.

Example 4-12. Reading keyboard modifiers

if (Keyboard.Modifiers & ModifierKeys.Control) != 0) {
   
isCopy = true;
}

Keyboardalso provides theIsKeyDownandIsKeyUpmethods, which let you query the state of any individual key, as shown in Example 4-13.

Example 4-13. Reading individual key state

bool homeKeyPressed = Keyboard.IsKeyDown(Key.Home);

You can also discover which element has the keyboard focus, using the staticFocusedElementproperty, or set the focus into a particular element by calling theFocusmethod.

The state information returned byKeyboarddoes not represent the current state. It represents a snapshot of the state for the event currently being processed. This means that if for some reason, your application gets bogged down and gets slightly behind in processing messages, the keyboard state will remain consistent.

As an example of why this is important, consider a drag operation where the Ctrl key determines whether the operation is a move or a copy. To behave correctly, your mouse up handler needs to know the state the Ctrl key had when the mouse button was released, rather than the state that it’s in now. If the user releases the Ctrl key after letting go of the mouse button, but before your application has processed the mouse up event, the user will expect a copy operation to be performed, and he will be unhappy if the application performs a move simply because your code couldn’t keep up. By returning a snapshot of the keyboard state rather than its immediate state, theKeyboardclass saves you from this problem.

Ink Input

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

Table 4-3. Stylus and ink events

Event

Routing

Meaning

GotStylusCapture

Bubble

Element captured stylus.

LostStylusCapture

Bubble

Element lost stylus capture.

PreviewStylusButtonDown, StylusButtonDown

Tunnel, Bubble

Stylus button pressed while over element.

PreviewStylusButtonUp, StylusButtonUp

Tunnel, Bubble

Stylus button released while over element.

PreviewStylusDown, StylusDown

Tunnel, Bubble

Stylus touched screen while over element.

PreviewStylusUp, StylusUp

Tunnel, Bubble

Stylus left screen while over element.

StylusEnter

Direct

Stylus moved into element.

StylusLeave

Direct

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.

TheStylusclass provides a staticCapturemethod that works exactly the same as theMouse.Capturemethod described earlier. It also offersCaptured andDirectlyOverproperties that do the same for the stylus as the matching properties of theMouseclass do for the mouse.

There is an alternative way of dealing with stylus input. Instead of handling all of these low-level events yourself, you can use WPF’s high-level ink handling element,InkCanvas. Example 4-14 shows how little is required to add an ink input area to a WPF application.

Example 4-14. InkCanvas

<InkCanvas />

TheInkCanvas accepts free-form ink input. Figure 4-3 shows the InkCanvasin action. (It also demonstrates that I should probably stick to using the keyboard.)InkCanvasmakes all of the ink input available to your program through itsStrokes property. It is possible to connect this data to the handwriting recognition APIs in Windows, but that is beyond the scope of this book.


Figure 4-3.  InkCanvas

Commands

 

The input events we’ve examined give us a detailed view of user input directed at individual elements. However, it is often helpful to focus on what the user wants our application to do, rather than how she asked us to do it. WPF supports this through the command abstraction—a command is an action the application performs at the user’s request.

The way in which a command is invoked isn’t usually important. Whether the user presses Ctrl-C, selects the Edit -> Copy menu item, or clicks the Copy button on the toolbar, the application’s response should be the same in each case: it should copy the current selection to the clipboard. The event system we examined earlier in this chapter regards these three types of input as being unrelated, but WPF’s command system lets you treat them as different expressions of the same command.

The command system lets a UI element provide a single handler for a command, reducing clutter and improving the clarity of your code. It enables a more declarative style for UI elements; by associating aMenuItemorButtonwith a particular command, you are making a clearer statement of the intended behavior than you would by wiring upClick event handlers. Example 4-15 illustrates how commands can simplify things.

Example 4-15. Commands with a menu and text box

<DockPanel>
  <Menu DockPanel.Dock="Top">
    <MenuItem Header="_Edit">
     
<MenuItem Header="Cu_t" Command="ApplicationCommands.Cut" />
      <MenuItem Header="_Copy" Command="ApplicationCommands.Copy" />
      <MenuItem Header="_Paste" Command="ApplicationCommands.Paste" />

    </MenuItem>
  </Menu>
  <ToolBarTray DockPanel.Dock="Top">
    <ToolBar>
     
<Button Command="Cut" Content="Cut" />
     
<Button Command="Copy" Content="Copy" />
     
<Button Command="Paste" Content="Paste" />
    </ToolBar>
  </ToolBarTray>

  <TextBox />
</DockPanel>

Each menu item is associated with a command. This is all that’s required to invoke these clipboard operations on the text box; we don’t need any code or event handlers because theTextBoxclass has built-in handling for these commands. More subtly, keyboard shortcuts also work in this example: the built-in cut, copy, and paste commands are automatically associated with their standard keyboard shortcuts, so these work wherever you use a text box. WPF’s command system ensures that when commands are invoked, they are delivered to the appropriate target, which in this case is the text box.

You are not obliged to use commands. You may already have classes to represent this idea in your own frameworks, and if WPF’s command abstraction does not suit your needs, you can just handle the routed events offered by menu items, buttons, and toolbars instead. But for most applications, commands simplify the way your application deals with user input.

There are five concepts at the heart of the command system:

Command object
  
An object identifying a particular command, such as
   copy or paste

Input binding
  
An association between a particular input (e.g., Ctrl-
   C) and a command (e.g., Copy)

Command source
  
The object that invoked the command, such as a
   Button, or an input binding

Command target
  
The UI element that will be asked to execute the
   command—typically the control that had the keyboard
   focus when the command was invoked

Command binding
  
A declaration that a particular UI element knows how
   to handle a particular command

Not all of these features are explicitly visible in Example 4-15—the command bindings are buried inside the text box’s implementation, and although input bindings are in use (Ctrl-C will work just fine, for example), they’ve been set up implicitly by WPF. To make it a bit easier to see all of the pieces, let’s look at a slightly more complex example that uses all five concepts explicitly (see Example 4-16).

Example 4-16. Basic command handling

<!-- XAML -->
<Window ...>
  <Grid>
    <Button Command="ApplicationCommands.Properties"
                  
Content="_Properties"/>
  </Grid>
</Window>
// Codebehind
public partial class Window1 : Window {

    public Window1(){
        InitializeComponent();

       InputBinding ib = new InputBinding(
        ApplicationCommands.Properties,
        new KeyGesture(Key.Enter, ModifierKeys.Alt)); 
       this.InputBindings.Add(ib);

       CommandBinding cb = new CommandBinding(ApplicationCommands.Properties); 
       cb.Executed += new ExecutedRoutedEventHandler(cb_Executed);
       this.CommandBindings.Add(cb);
   
}

    void cb_Executed(object sender, ExecutedRoutedEventArgs e) {
        MessageBox.Show("Properties");
    }
 

}

This example uses the standardApplicationCommands.Propertiescommand object. Applications that support this command would typically open a property panel or window for the selected item. The XAML in this example associates a button with this command object; clicking the button will invoke the command. The code behind establishes an input binding so that the Alt-Enter shortcut may also be used to invoke the command. Our example, therefore, has two potential command sources: the button and the input binding. The command target in this particular example will be the button; this is true even if the command is invoked with a keyboard shortcut, because the button is the only element in the window capable of having the keyboard focus. However, the button doesn’t know how to handle this command, so it will bubble up to the window, much like an input event. The window does know how to handle the command; it has declared this by creating a command binding with a handler attached to the binding’sExecuted event. This handler will be called when the user invokes the command.

Now that we’ve seen all five features in use, we’ll examine each one in more detail.

Please check back next week for the continuation of this series.

blog comments powered by Disqus
.NET ARTICLES

- .Net 4.5 Brings Changes
- Understanding Events in VB.NET
- Objects, Properties, Events and Methods in V...
- Install Visual Web Developer Express 2010
- Microsoft Gadgeteer an Open Source Alternati...
- Best DotNetNuke Modules
- Facebook Image Viewer in Visual Basic
- Murach`s ADO.NET 4 Database Programming with...
- 5 Must Have Visual Studio 2010 Extensions
- Dynamic Web Applications with ASP.NET Mono u...
- PDFSharp: HTML to PDF in ASP.NET 3.5 using V...
- Using the PDFSharp Library in ASP.NET 3.5 wi...
- Sending Email in ASP.NET 3.5 using VB.NET wi...
- ASP.NET 3.5 Role Based Security and User Aut...
- Creating ASP.NET Login Web Pages and Basic C...

ASP Web Hosting ASP.Net Web Hosting Windows Web Hosting
ASP Free Forums 
 RSS  Tutorials RSS
 RSS  Forums RSS
 RSS  All Feeds
Site Map 
Request Media Kit
Write For Us Get Paid 
Weekly Newsletter
 
Developer Updates  
Free Website Content 
Privacy Policy 
Support 


© 2003-2012 by Developer Shed. All rights reserved. DS Cluster 7 - Follow our Sitemap
Most Popular Topics
All ASP.Net Tutorials