Partilhar via


Input Overview

The Windows Presentation Foundation (WPF) subsystem provides a powerful API for obtaining input from a variety of devices, including the mouse, keyboard, and stylus.

This topic describes the services provided by WPF and explains the architecture of the input systems.

Este tópico contém as seguintes seções.

  • Input API
  • Event Routing
  • Handling Input Events
  • Text Input
  • Foco
  • Mouse Position
  • Mouse Capture
  • Comandos
  • The Input System and Base Elements
  • O Que Mais Há
  • Tópicos relacionados

Input API

De entrada principalAPI exposição é encontrada nas classes de elemento base: UIElement, ContentElement, FrameworkElement, e FrameworkContentElement. For more information about the base elements, see Visão geral sobre elementos base. These classes provide functionality for input events related to key presses, mouse buttons, mouse wheel, mouse movement, focus management, and mouse capture, to name a few. Colocando a entrada API em elementos base, em vez de tratar eventos de entrada tudo sistema autônomo um serviço, a arquitetura entrada permite que sistema autônomo eventos de entrada para ser originado por um objeto específico na interface do usuário e para oferecer suporte a um esquema de roteamento do evento na qual mais de um elemento tem a oportunidade para manipular um evento de entrada. Muitos eventos de entrada têm um emparelhar de eventos associados a eles. For example, the key down event is associated with the KeyDown and PreviewKeyDown events. The difference in these events is in how they are routed to the target element. Preview events tunneling down the element tree from the root element to the target element. Bubbling events bubbling up from the target element to the root element. Event routing in WPF is discussed in more detail later in this overview and in the Visão geral sobre eventos roteados.

Keyboard and Mouse Classes

In addition to the input API on the base element classes, the Keyboard class and Mouse classes provide additional API for working with keyboard and mouse input.

Examples of input API on the Keyboard class are the Modifiers property, which returns the ModifierKeys currently pressed, and the IsKeyDown method, which determines whether a specified key is pressed.

The following example uses the GetKeyStates method to determine if a Key is in the down state.

// Uses the Keyboard.GetKeyStates to determine if a key is down.
// A bitwise AND operation is used in the comparison. 
// e is an instance of KeyEventArgs.
if ((Keyboard.GetKeyStates(Key.Return) & KeyStates.Down) > 0)
{
    btnNone.Background = Brushes.Red;
}

Examples of input API on the Mouse class are MiddleButton, which obtains the state of the middle mouse button, and DirectlyOver, which gets the element the mouse pointer is currently over.

The following example determines whether the LeftButton on the mouse is in the Pressed state.

if (Mouse.LeftButton == MouseButtonState.Pressed)
{
    UpdateSampleResults("Left Button Pressed");
}

The Mouse and Keyboard classes are covered in more detail throughout this overview.

Stylus Input

WPF has integrated support for the Stylus. The Stylus é uma entrada à caneta feita popular pela Tablet PC. WPF aplicativos podem tratar a caneta sistema autônomo um mouse com o mouse API, mas WPF também expõe uma abstração de dispositivo de caneta que usam um modelo semelhante ao teclado e mouse. All stylus-related APIs contain the word "Stylus".

Because the stylus can act as a mouse, applications that support only mouse input can still obtain some level of stylus support automatically. When the stylus is used in such a manner, the application is given the opportunity to handle the appropriate stylus event and then handles the corresponding mouse event. In addition, higher-level services such as ink input are also available through the stylus device abstraction. For more information about ink as input, see Getting Started with Ink.

Event Routing

A FrameworkElement can contain other elements as child elements in its content model, forming a tree of elements. In WPF, the parent element can participate in input directed to its child elements or other descendants by handing events. This is especially useful for building controls out of smaller controls, a process known as "control composition" or "compositing." For more information about element trees and how element trees relate to event routes, see Árvores em WPF.

Event routing is the process of forwarding events to multiple elements, so that a particular object or element along the route can choose to offer a significant response (through handling) to an event that might have been sourced by a different element. Roteados eventos use um dos três mecanismos de roteamento: direta, bubbling e encapsulamento. In direct routing, the source element is the only element notified, and the event is not routed to any other elements. However, the direct routed event still offers some additional capabilities that are only present for routed events as opposed to standard CLR events. Bubbling works up the element tree by first notifying the element that sourced the event, then the parent element, and so on. Tunneling starts at the root of the element tree and works down, ending with the original source element. For more information about routed events, see Visão geral sobre eventos roteados.

WPF input events generally come in pairs that consists of a tunneling event and a bubbling event. Tunneling events are distinguished from bubbling events with the "Preview" prefix. For instance, PreviewMouseMove is the tunneling version of a mouse move event and MouseMove is the bubbling version of this event. This event pairing is a convention that is implemented at the element level and is not an inherent capability of the WPF event system. For details, see the WPF Input Events section in Visão geral sobre eventos roteados.

Handling Input Events

To receive input on an element, an event handler must be associated with that particular event. In XAML Isso é simples: referência do nome do evento sistema autônomo um atributo do elemento será aguardando esse evento. Then, you set the value of the attribute to the name of the event handler that you define, based on a delegate. The event handler must be written in code such as C# and can be included in a code-behind file.

Keyboard events occur when the operating system reports key actions that occur while keyboard focus is on an element. Caneta de mouse e eventos cada se enquadram em duas categorias: eventos que muda de relatório na posição do ponteiro em relação ao elemento e eventos que muda de relatório no estado dos botões do dispositivo.

Keyboard Input Event Example

O exemplo a seguir atende a um pressionamento de tecla de direção para a esquerda. A StackPanel is created that has a Button. An event handler to listen for the left arrow key press is attached to the Button instance.

The first section of the example creates the StackPanel and the Button and attaches the event handler for the KeyDown.

<StackPanel>
  <Button Background="AliceBlue"
          KeyDown="OnButtonKeyDown"
          Content="Button1"/>
</StackPanel>
// Create the UI elements.
StackPanel keyboardStackPanel = new StackPanel();
Button keyboardButton1 = new Button();

// Set properties on Buttons.
keyboardButton1.Background = Brushes.AliceBlue;
keyboardButton1.Content = "Button 1";

// Attach Buttons to StackPanel.
keyboardStackPanel.Children.Add(keyboardButton1);

// Attach event handler.
keyboardButton1.KeyDown += new KeyEventHandler(OnButtonKeyDown);

The second section is written in code and defines the event handler. When the left arrow key is pressed and the Button has keyboard focus, the handler runs and the Background color of the Button is changed. If the key is pressed, but it is not the left arrow key, the Background color of the Button is changed back to its starting color.

private void OnButtonKeyDown(object sender, KeyEventArgs e)
{
    Button source = e.Source as Button;
    if (source != null)
    {
        if (e.Key == Key.Left)
        {
            source.Background = Brushes.LemonChiffon;
        }
        else
        {
            source.Background = Brushes.AliceBlue;
        }
    }
}

Mouse Input Event Example

In the following example, the Background color of a Button is changed when the mouse pointer enters the Button. The Background color is restored when the mouse leaves the Button.

The first section of the example creates the StackPanel and the Button control and attaches the event handlers for the MouseEnter and MouseLeave events to the Button.

<StackPanel>
  <Button Background="AliceBlue"
          MouseEnter="OnMouseExampleMouseEnter"
          MouseLeave="OnMosueExampleMouseLeave">Button

  </Button>
</StackPanel>
// Create the UI elements.
StackPanel mouseMoveStackPanel = new StackPanel();
Button mouseMoveButton = new Button();

// Set properties on Button.
mouseMoveButton.Background = Brushes.AliceBlue;
mouseMoveButton.Content = "Button";

// Attach Buttons to StackPanel.
mouseMoveStackPanel.Children.Add(mouseMoveButton);

// Attach event handler.
mouseMoveButton.MouseEnter += new MouseEventHandler(OnMouseExampleMouseEnter);
mouseMoveButton.MouseLeave += new MouseEventHandler(OnMosueExampleMouseLeave);

A segunda seção do exemplo é escrita em código e define o evento manipuladores. When the mouse enters the Button, the Background color of the Button is changed to SlateGray. When the mouse leaves the Button, the Background color of the Button is changed back to AliceBlue.

private void OnMouseExampleMouseEnter(object sender, MouseEventArgs e)
{
    // Cast the source of the event to a Button.
    Button source = e.Source as Button;

    // If source is a Button.
    if (source != null)
    {
        source.Background = Brushes.SlateGray;
    }
}
private void OnMosueExampleMouseLeave(object sender, MouseEventArgs e)
{
    // Cast the source of the event to a Button.
    Button source = e.Source as Button;

    // If source is a Button.
    if (source != null)
    {
        source.Background = Brushes.AliceBlue;
    }
}

Text Input

The TextInput event enables you to listen for text input in a device-independent manner. The keyboard is the primary means of text input, but speech, handwriting, and other input devices can generate text input also.

For keyboard input, WPF first sends the appropriate KeyDown / KeyUp events. If those events are not handled and the key is textual (rather than a control key such as directional arrows or function keys), then a TextInput event is raised. There is not always a simple one-to-one mapping between KeyDown/KeyUp and TextInput events because multiple keystrokes can generate a single character of text input and single keystrokes can generate multi-character strings. This is especially true for languages such as Chinese, Japanese, and Korean which use Editores de Método de Entrada (IME) to generate the thousands of possible characters in their corresponding alphabets.

When WPF sends a KeyUp/KeyDown event, Key is set to Key.System if the keystrokes could become part of a TextInput event (if ALT+S is pressed, for example). This allows code in a KeyDown event handler to check for Key.System and, if found, leave processing for the handler of the subsequently raised TextInput event. In these cases, the various properties of the TextCompositionEventArgs argument can be used to determine the original keystrokes. Similarly, if an IME is active, Key has the value of Key.ImeProcessed, and ImeProcessedKey gives the original keystroke or keystrokes.

The following example defines a handler for the Click event and a handler for the KeyDown event,

The first segment of code or markup creates the user interface.

<StackPanel KeyDown="OnTextInputKeyDown">
  <Button Click="OnTextInputButtonClick"
          Content="Open" />
  <TextBox> . . . </TextBox>
</StackPanel>
// Create the UI elements.
StackPanel textInputStackPanel = new StackPanel();
Button textInputeButton = new Button();
TextBox textInputTextBox = new TextBox();
textInputeButton.Content = "Open";

// Attach elements to StackPanel.
textInputStackPanel.Children.Add(textInputeButton);
textInputStackPanel.Children.Add(textInputTextBox);

// Attach event handlers.
textInputStackPanel.KeyDown += new KeyEventHandler(OnTextInputKeyDown);
textInputeButton.Click += new RoutedEventHandler(OnTextInputButtonClick);

The second segment of code contains the event handlers

private void OnTextInputKeyDown(object sender, KeyEventArgs e)
{
    if (e.Key == Key.O && Keyboard.Modifiers == ModifierKeys.Control)
    {
        handle();
        e.Handled = true;
    }
}

private void OnTextInputButtonClick(object sender, RoutedEventArgs e)
{
    handle();
    e.Handled = true;
} 

public void handle()
{
    MessageBox.Show("Pretend this opens a file");
}

Because input events bubble up the event route, the StackPanel receives the input regardless of which element has keyboard focus. The TextBox control is notified first and the OnTextInputKeyDown handler is called only if the TextBox did not handle the input. If the PreviewKeyDown event is used instead of the KeyDown event, the OnTextInputKeyDown handler is called first.

In this example, the handling logic is written two times—one time for CTRL+O, and again for button's click event. This can be simplified by using commands, instead of handling the input events directly. Commands are discussed in this overview and in Visão geral de Comando.

Foco

Há dois principais conceitos que pertencem ao foco no WPF: foco do teclado e o foco lógico.

Keyboard Focus

Keyboard focus refers to the element that is receiving keyboard input. There can be only one element on the whole desktop that has keyboard focus. In WPF, the element that has keyboard focus will have IsKeyboardFocused set to true. The static Keyboard method FocusedElement returns the element that currently has keyboard focus.

Keyboard focus can be obtained by tabbing to an element or by clicking the mouse on certain elements, such as a TextBox. O foco do teclado também pode ser obtido por meio de programação usando o método Focus na classe Keyboard. Focus tenta dar o foco do teclado elemento especificado. The element returned by Focus is the element that currently has keyboard focus.

In order for an element to obtain keyboard focus the Focusable property and the IsVisible properties must be set to true. Some classes, such as Panel, have Focusable set to false by default; therefore, you may have to set this property to true if you want that element to be able to obtain focus.

The following example uses Focus to set keyboard focus on a Button. The recommended place to set initial focus in an application is in the Loaded event handler.

private void OnLoaded(object sender, RoutedEventArgs e)
{
    // Sets keyboard focus on the first Button in the sample.
    Keyboard.Focus(firstButton);
}

For more information about keyboard focus, see Visão geral sobre Foco.

Logical Focus

Logical focus refers to the FocusManager.FocusedElement in a focus scope. There can be multiple elements that have logical focus in an application, but there may only be one element that has logical focus in a particular focus scope.

A focus scope is a container element that keeps track of the FocusedElement within its scope. When focus leaves a focus scope, the focused element will lose keyboard focus but will retain logical focus. When focus returns to the focus scope, the focused element will obtain keyboard focus. This allows for keyboard focus to be changed between multiple focus scopes but insures that the focused element within the focus scope remains the focused element when focus returns.

An element can be turned into a focus scope in Extensible Application Markup Language (XAML) by setting the FocusManager attached property IsFocusScope to true, or in code by setting the attached property by using the SetIsFocusScope method.

The following example makes a StackPanel into a focus scope by setting the IsFocusScope attached property.

<StackPanel Name="focusScope1" 
            FocusManager.IsFocusScope="True"
            Height="200" Width="200">
  <Button Name="button1" Height="50" Width="50"/>
  <Button Name="button2" Height="50" Width="50"/>
</StackPanel>
StackPanel focuseScope2 = new StackPanel();
FocusManager.SetIsFocusScope(focuseScope2, true);

Classes in WPF which are focus scopes by default are Window, Menu, ToolBar, and ContextMenu.

An element that has keyboard focus will also have logical focus for the focus scope it belongs to; therefore, setting focus on an element with the Focus method on the Keyboard class or the base element classes will attempt to give the element keyboard focus and logical focus.

To determine the focused element in a focus scope, use GetFocusedElement. To change the focused element for a focus scope, use SetFocusedElement.

For more information about logical focus, see Visão geral sobre Foco.

Mouse Position

The WPF input API provides helpful information with regard to coordinate spaces. For example, coordinate (0,0) is the upper-left coordinate, but the upper-left of which element in the tree? The element that is the input target? The element you attached your event handler to? Or something else? To avoid confusion, the WPF input API requires that you specify your frame of reference when you work with coordinates obtained through the mouse. The GetPosition method returns the coordinate of the mouse pointer relative to the specified element.

Mouse Capture

Mouse devices specifically hold a modal characteristic known as mouse capture. Mouse capture is used to maintain a transitional input state when a drag-and-drop operation is started, so that other operations involving the nominal on-screen position of the mouse pointer do not necessarily occur. During the drag, the user cannot click without aborting the drag-and-drop, which makes most mouseover cues inappropriate while the mouse capture is held by the drag origin. The input system exposes APIs that can determine mouse capture state, as well as APIs that can force mouse capture to a specific element, or clear mouse capture state. For more information on drag-and-drop operations, see Visão geral sobre arrastar e soltar.

Comandos

Commands enable input handling at a more semantic level than device input. Commands are simple directives, such as Cut, Copy, Paste, or Open. Commands are useful for centralizing your command logic. The same command might be accessed from a Menu, on a ToolBar, or through a keyboard shortcut. Commands also provide a mechanism for disabling controls when the command becomes unavailable.

RoutedCommand is the WPF implementation of ICommand. Quando um RoutedCommand é executado, um PreviewExecuted e um Executed eventos são gerados no seu destino, qual túnel e bolhas através da árvore de elementos, como Outros entrada. Se um comando de destino não estiver definido, o elemento com o foco do teclado será seu destino. The logic that performs the command is attached to a CommandBinding. When an Executed event reaches a CommandBinding for that specific command, the ExecutedRoutedEventHandler on the CommandBinding is called. This handler performs the action of the command.

For more information on commanding, see Visão geral de Comando.

WPF provides a library of common commands which consists of ApplicationCommands, MediaCommands, ComponentCommands, NavigationCommands, and EditingCommands, or you can define your own.

The following example shows how to set up a MenuItem so that when it is clicked it will invoke the Paste command on the TextBox, assuming the TextBox has keyboard focus.

<StackPanel>
  <Menu>
    <MenuItem Command="ApplicationCommands.Paste" />
  </Menu>
  <TextBox />
</StackPanel>
// Creating the UI objects
StackPanel mainStackPanel = new StackPanel();
TextBox pasteTextBox = new TextBox();
Menu stackPanelMenu = new Menu();
MenuItem pasteMenuItem = new MenuItem();

// Adding objects to the panel and the menu
stackPanelMenu.Items.Add(pasteMenuItem);
mainStackPanel.Children.Add(stackPanelMenu);
mainStackPanel.Children.Add(pasteTextBox);

// Setting the command to the Paste command
pasteMenuItem.Command = ApplicationCommands.Paste;

For more information about commands in WPF, see Visão geral de Comando.

The Input System and Base Elements

Input events such as the attached events defined by the Mouse, Keyboard, and Stylus classes are raised by the input system and injected into a particular position in the object model based on hit testing the visual tree at run time.

Each of the events that Mouse, Keyboard, and Stylus define as an attached event is also re-exposed by the base element classes UIElement and ContentElement as a new routed event. The base element routed events are generated by classes handling the original attached event and reusing the event data.

When the input event becomes associated with a particular source element through its base element input event implementation, it can be routed through the remainder of an event route that is based on a combination of logical and visual tree objects, and be handled by application code. Generally, it is more convenient to handle these device-related input events using the routed events on UIElement and ContentElement, because you can use more intuitive event handler syntax both in XAML and in code. Você pode escolher manipular o evento anexado que iniciou o processo em vez disso, mas enfrenta diversos problemas: o evento anexado pode ser marcado manipulado pelo tratamento de classe do elemento base e você precisa usar métodos acessadores em vez da sintaxe do evento true para anexar manipuladores para eventos anexados.

O Que Mais Há

You now have several techniques to handle input in WPF. You should also have an improved understanding of the various types of input events and the routed event mechanisms used by WPF.

Additional resources are available that explain WPF framework elements and event routing in more detail. Consulte as seguintes visões gerais para obter mais informações, Visão geral de Comando, Visão geral sobre FocoVisão geral sobre elementos baseÁrvores em WPF, e Visão geral sobre eventos roteados.

Consulte também

Conceitos

Visão geral sobre Foco

Visão geral de Comando

Visão geral sobre eventos roteados

Visão geral sobre elementos base

Outros recursos

Propriedades