输入概述Input Overview

@No__t 1 子系统提供了一个功能强大的 API,用于从各种设备(包括鼠标、键盘、触摸和触笔)获取输入。The Windows Presentation Foundation (WPF)Windows Presentation Foundation (WPF) subsystem provides a powerful API for obtaining input from a variety of devices, including the mouse, keyboard, touch, and stylus. 本主题介绍了 WPFWPF 提供的服务,并说明了输入系统的体系结构。This topic describes the services provided by WPFWPF and explains the architecture of the input systems.

输入 APIInput API

主输入 API 公开内容在基本元素类上找到: UIElementContentElementFrameworkElement 和 @no__t。The primary input API exposure is found on the base element classes: UIElement, ContentElement, FrameworkElement, and FrameworkContentElement. 有关基元素的详细信息,请参阅基元素概述For more information about the base elements, see Base Elements Overview. 这些类提供有关输入事件(例如按键、鼠标按钮、鼠标滚轮、鼠标移动、焦点管理和鼠标捕获等)的功能。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. 通过将输入 API 放在基元素上,而不是将所有输入事件视为一项服务,输入体系结构使输入事件可以通过 UI 中的特定对象来提供,并支持一个事件路由方案,使多个元素具有 opportunity 来处理输入事件。By placing the input API on the base elements, rather than treating all input events as a service, the input architecture enables the input events to be sourced by a particular object in the UI, and to support an event routing scheme whereby more than one element has an opportunity to handle an input event. 许多输入事件都具有与之相关联的一对事件。Many input events have a pair of events associated with them. 例如,键按下事件与 @no__t 0 和 @no__t 1 事件关联。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 tunnel down the element tree from the root element to the target element. 冒泡事件从目标元素到根元素向上进行冒泡操作。Bubbling events bubble up from the target element to the root element. 本概述后面部分和路由事件概述中更详细地讨论了 WPFWPF 中的事件路由。Event routing in WPFWPF is discussed in more detail later in this overview and in the Routed Events Overview.

键盘和鼠标类Keyboard and Mouse Classes

除了基本元素类上的输入 API 外,@no__t 的类和 @no__t 类还提供了用于使用键盘和鼠标输入的其他 API。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.

@No__t-0 类上输入 API 的示例为 Modifiers 属性,该属性返回当前按下的 @no__t)和 @no__t 3 方法,该方法确定是否按下了指定的键。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.

下面的示例使用 GetKeyStates 方法来确定 @no__t 是否处于关闭状态。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;
}
' 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) And KeyStates.Down) > 0 Then
    btnNone.Background = Brushes.Red

@No__t-0 类上输入 API 的示例 @no__t 为-1,它获取鼠标中键的状态,@no__t 为-2,这会获取鼠标指针当前悬停的元素。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.

下面的示例确定鼠标上的 @no__t 0 是否处于 @no__t 状态。The following example determines whether the LeftButton on the mouse is in the Pressed state.

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

本概述中更详细地介绍了 Mouse 和 @no__t 1 类。The Mouse and Keyboard classes are covered in more detail throughout this overview.

触笔输入Stylus Input

WPFWPF 对 @no__t 的集成支持。has integrated support for the Stylus. @No__t-0 是 Tablet PC 流行的笔输入。The Stylus is a pen input made popular by the Tablet PC. @no__t 0 应用程序可以通过使用鼠标 API 将触笔视为鼠标,但 WPFWPF 还会公开使用类似于键盘和鼠标的模型的触笔设备抽象。WPFWPF applications can treat the stylus as a mouse by using the mouse API, but WPFWPF also exposes a stylus device abstraction that use a model similar to the keyboard and mouse. 与触笔相关的所有 Api 都包含 "触笔" 一词。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

@No__t-0 可以在其内容模型中包含作为子元素的其他元素,从而形成元素树。A FrameworkElement can contain other elements as child elements in its content model, forming a tree of elements. WPFWPF 中,父元素可以通过处理事件来参与定向到其子元素或其他后代的输入。In WPFWPF, 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." 有关元素树以及元素树如何与事件路由关联的详细信息,请参阅 WPF 中的树For more information about element trees and how element trees relate to event routes, see Trees in 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. 路由事件使用三种路由机制的其中一种:直接、浮升和隧道。Routed events use one of three routing mechanisms: direct, bubbling, and tunneling. 在直接路由中,源元素是收到通知的唯一元素,事件不会路由至任何其他元素。In direct routing, the source element is the only element notified, and the event is not routed to any other elements. 但是,直接路由事件仍会提供一些附加功能,这些功能仅适用于路由事件,而不是标准 CLR 事件。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 Routed Events Overview.

WPFWPF 输入事件通常成对出现,由一个隧道事件和一个冒泡事件组成。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. 例如,@no__t 为鼠标移动事件的隧道版本,MouseMove 是此事件的冒泡版本。For instance, PreviewMouseMove is the tunneling version of a mouse move event and MouseMove is the bubbling version of this event. 此事件配对是在元素级别实现的一种约定,不是 WPFWPF 事件系统的固有功能。This event pairing is a convention that is implemented at the element level and is not an inherent capability of the WPFWPF event system. 有关详细信息,请参阅路由事件概述中的 WPF 输入事件部分。For details, see the WPF Input Events section in Routed Events Overview.

处理输入事件Handling Input Events

若要在元素上接收输入,必须将事件处理程序与该特定事件关联。To receive input on an element, an event handler must be associated with that particular event. XAMLXAML 中,这很简单:将事件的名称作为要侦听此事件的元素的特性进行引用。In XAMLXAML this is straightforward: you reference the name of the event as an attribute of the element that will be listening for this event. 然后,根据委托,将特性的值设置为所定义的事件处理程序的名称。Then, you set the value of the attribute to the name of the event handler that you define, based on a delegate. 事件处理程序必须用代码(如) C#编写,并且可以包含在代码隐藏文件中。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. 鼠标和触笔事件分别分为两类:报告指针位置相对于元素的变化的事件,和报告设备按钮状态的变化的事件。Mouse and stylus events each fall into two categories: events that report changes in pointer position relative to the element, and events that report changes in the state of device buttons.

键盘输入事件示例Keyboard Input Event Example

以下示例侦听按下向左键的操作。The following example listens for a left arrow key press. @No__t 创建一个 @no__t 为1的。A StackPanel is created that has a Button. 用于侦听按下箭头键的事件处理程序已附加到 Button 实例。An event handler to listen for the left arrow key press is attached to the Button instance.

该示例的第一部分创建 @no__t 0 和 Button,并附加 @no__t 的事件处理程序。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);
' Create the UI elements.
Dim keyboardStackPanel As New StackPanel()
Dim keyboardButton1 As 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.
AddHandler keyboardButton1.KeyDown, AddressOf OnButtonKeyDown

第二部分用代码编写,定义了事件处理程序。The second section is written in code and defines the event handler. 按下向左键并 Button 具有键盘焦点时,处理程序将运行并更改 @no__t 的 @no__t 1 颜色。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. 如果按下了键,但它不是左箭头键,则 Button 的 @no__t 颜色将改回其起始颜色。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;
        }
    }
}
Private Sub OnButtonKeyDown(ByVal sender As Object, ByVal e As KeyEventArgs)
    Dim source As Button = TryCast(e.Source, Button)
    If source IsNot Nothing Then
        If e.Key = Key.Left Then
            source.Background = Brushes.LemonChiffon
        Else
            source.Background = Brushes.AliceBlue
        End If
    End If
End Sub

鼠标输入事件示例Mouse Input Event Example

在下面的示例中,当鼠标指针进入 Button 时,将更改 @no__t 的 @no__t 0 颜色。In the following example, the Background color of a Button is changed when the mouse pointer enters the Button. 当鼠标离开 @no__t 时,将还原 @no__t 的颜色。The Background color is restored when the mouse leaves the Button.

该示例的第一部分创建 @no__t 0 和 Button 控件,并将 @no__t 2 和 3 @no__t 事件的事件处理程序附加到 @no__t。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);
' Create the UI elements.
Dim mouseMoveStackPanel As New StackPanel()
Dim mouseMoveButton As New Button()

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

' Attach Buttons to StackPanel.
mouseMoveStackPanel.Children.Add(mouseMoveButton)

' Attach event handler.
AddHandler mouseMoveButton.MouseEnter, AddressOf OnMouseExampleMouseEnter
AddHandler mouseMoveButton.MouseLeave, AddressOf OnMosueExampleMouseLeave

该示例的第二部分用代码编写,定义了事件处理程序。The second section of the example is written in code and defines the event handlers. 当鼠标进入 Button 时,Button 的 @no__t 颜色将更改为 @no__t。When the mouse enters the Button, the Background color of the Button is changed to SlateGray. 当鼠标离开 Button 时,@no__t 的第 1 @no__t 颜色将改回为 AliceBlueWhen 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 Sub OnMouseExampleMouseEnter(ByVal sender As Object, ByVal e As MouseEventArgs)
    ' Cast the source of the event to a Button.
    Dim source As Button = TryCast(e.Source, Button)

    ' If source is a Button.
    If source IsNot Nothing Then
        source.Background = Brushes.SlateGray
    End If
End Sub
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;
    }
}
Private Sub OnMosueExampleMouseLeave(ByVal sender As Object, ByVal e As MouseEventArgs)
    ' Cast the source of the event to a Button.
    Dim source As Button = TryCast(e.Source, Button)

    ' If source is a Button.
    If source IsNot Nothing Then
        source.Background = Brushes.AliceBlue
    End If
End Sub

文本输入Text Input

通过 TextInput 事件,你可以以与设备无关的方式侦听文本输入。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.

对于键盘输入,WPFWPF 首先发送适当的 @no__t @ no__t-2 @ no__t 事件。For keyboard input, WPFWPF first sends the appropriate KeyDown/KeyUp events. 如果未处理这些事件,并且键是文本(而不是方向箭头或函数键等控制键),则会引发 @no__t 的事件。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. KeyDown @ no__t-1 @ no__t 和 @no__t 3 事件之间,并不总是有一种简单的一对一映射,因为多个击键可以生成一个文本输入字符,而单个击键可以生成多个字符的字符串。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. 对于中文、日语和韩语等语言,使用输入法编辑器(Ime)在其相应的字母表中生成成千上万个可能的字符时尤其如此。This is especially true for languages such as Chinese, Japanese, and Korean which use Input Method Editors (IMEs) to generate the thousands of possible characters in their corresponding alphabets.

WPFWPF 发送 @no__t @ no__t-2 @ no__t 事件时,如果击键可能成为 @no__t 事件的一部分(例如,按下 ALT + S),Key 设置为 Key.SystemWhen WPFWPF 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). 这允许 @no__t 0 事件处理程序中的代码检查 @no__t 为-1,如果找到,则为后面引发的 @no__t 2 事件的处理程序保留处理。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. 在这些情况下,可以使用 TextCompositionEventArgs 参数的各种属性来确定原始击键。In these cases, the various properties of the TextCompositionEventArgs argument can be used to determine the original keystrokes. 同样,如果输入法处于活动状态,Key 的值为 Key.ImeProcessedImeProcessedKey 则提供原始击键或击键。Similarly, if an IME is active, Key has the value of Key.ImeProcessed, and ImeProcessedKey gives the original keystroke or keystrokes.

下面的示例为 Click 事件定义处理程序,并为 @no__t 1 事件定义处理程序。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);
' Create the UI elements.
Dim textInputStackPanel As New StackPanel()
Dim textInputeButton As New Button()
Dim textInputTextBox As New TextBox()
textInputeButton.Content = "Open"

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

' Attach event handlers.
AddHandler textInputStackPanel.KeyDown, AddressOf OnTextInputKeyDown
AddHandler textInputeButton.Click, AddressOf 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");
}
Private Sub OnTextInputKeyDown(ByVal sender As Object, ByVal e As KeyEventArgs)
    If e.Key = Key.O AndAlso Keyboard.Modifiers = ModifierKeys.Control Then
        handle()
        e.Handled = True
    End If
End Sub

Private Sub OnTextInputButtonClick(ByVal sender As Object, ByVal e As RoutedEventArgs)
    handle()
    e.Handled = True
End Sub

Public Sub handle()
    MessageBox.Show("Pretend this opens a file")
End Sub

由于输入事件向上冒泡事件路由,因此 StackPanel 接收输入,而不考虑哪个元素具有键盘焦点。Because input events bubble up the event route, the StackPanel receives the input regardless of which element has keyboard focus. 将首先通知 @no__t 0 控件,并且仅当 TextBox 未处理输入时,才调用 OnTextInputKeyDown 处理程序。The TextBox control is notified first and the OnTextInputKeyDown handler is called only if the TextBox did not handle the input. 如果使用 @no__t 0 事件而不是 KeyDown 事件,则首先调用 @no__t 2 处理程序。If the PreviewKeyDown event is used instead of the KeyDown event, the OnTextInputKeyDown handler is called first.

在此示例中,处理逻辑写入了两次,分别针对 CTRL+O和按钮的单击事件。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 Commanding Overview.

触摸和操作Touch and Manipulation

Windows 7 操作系统中的新硬件和 API 使应用程序能够同时接收来自多个触控的输入。New hardware and API in the Windows 7 operating system provide applications the ability to receive input from multiple touches simultaneously. WPFWPF 通过在触摸发生时引发事件,从而使应用程序能够以类似于响应其他输入(例如鼠标或键盘)的方式来检测和响应触摸设备。enables applications to detect and respond to touch in a manner similar to responding to other input, such as the mouse or keyboard, by raising events when touch occurs.

发生触摸时,WPFWPF 将公开两种类型的事件:触摸事件和操作事件。WPFWPF exposes two types of events when touch occurs: touch events and manipulation events. 触摸事件提供有关触摸屏上每个手指及其移动的原始数据。Touch events provide raw data about each finger on a touchscreen and its movement. 操作事件将输入解释为特定操作。Manipulation events interpret the input as certain actions. 本部分将讨论这两种类型的事件。Both types of events are discussed in this section.

先决条件Prerequisites

需要以下组件才能开发响应触摸的应用程序。You need the following components to develop an application that responds to touch.

  • Visual Studio 2010。Visual Studio 2010.

  • Windows 7。Windows 7.

  • 支持 Windows 触控的设备,如触摸屏。A device, such as a touchscreen, that supports Windows Touch.

术语Terminology

讨论触摸时使用了以下术语。The following terms are used when touch is discussed.

  • 触摸是 Windows 7 可识别的一种用户输入。Touch is a type of user input that is recognized by Windows 7. 通常,将手指放在触敏式屏幕上会触发触摸。Usually, touch is initiated by putting fingers on a touch-sensitive screen. 请注意,如果设备仅将手指的位置和移动转换为鼠标输入,则笔记本电脑上常用的触摸板等设备不支持触摸。Note that devices such as a touchpad that is common on laptop computers do not support touch if the device merely converts the finger's position and movement as mouse input.

  • 多点触摸是同时发生在多个点上的触摸。Multitouch is touch that occurs from more than one point simultaneously. Windows 7 和 WPFWPF 支持多点触摸。Windows 7 and WPFWPF supports multitouch. WPFWPF 文档中每当论及触摸时,相关概念均适用于多点触摸。Whenever touch is discussed in the documentation for WPFWPF, the concepts apply to multitouch.

  • 当触摸被解释为应用于对象的实际操作时,就发生了操作A manipulation occurs when touch is interpreted as a physical action that is applied to an object. WPFWPF 中,操作事件将输入解释为转换、扩展或旋转操作。In WPFWPF, manipulation events interpret input as a translation, expansion, or rotation manipulation.

  • touch device 表示产生触摸输入的设备,例如触摸屏上的一根手指。A touch device represents a device that produces touch input, such as a single finger on a touchscreen.

响应触摸的控件Controls that Respond to Touch

如果以下控件的内容延伸到视图之外,则可以通过在控件上拖动手指来滚动该控件。The following controls can be scrolled by dragging a finger across the control if it has content that is scrolled out of view.

@No__t-0 定义了 @no__t 1 附加属性,该属性使你能够指定是否水平、垂直、同时启用触控平移。The ScrollViewer defines the ScrollViewer.PanningMode attached property that enables you to specify whether touch panning is enabled horizontally, vertically, both, or neither. @No__t-0 属性指定当用户将手指从触摸屏上提起时,滚动速度变慢的速度。The ScrollViewer.PanningDeceleration property specifies how quickly the scrolling slows down when the user lifts the finger from the touchscreen. @No__t-0 附加属性指定滚动偏移与转换操作偏移的比率。The ScrollViewer.PanningRatio attached property specifies the ratio of scrolling offset to translate manipulation offset.

触摸事件Touch Events

基类 UIElementUIElement3DContentElement 定义可订阅的事件,使应用程序能够响应触控。The base classes, UIElement, UIElement3D, and ContentElement, define events that you can subscribe to so your application will respond to touch. 当应用程序将触摸解释为操作对象以外的其他操作时,触摸事件非常有用。Touch events are useful when your application interprets touch as something other than manipulating an object. 例如,使用户能够以一个或多个手指绘制的应用程序将订阅触摸事件。For example, an application that enables a user to draw with one or more fingers would subscribe to touch events.

所有三个类都定义了以下事件,其行为类似,而无论定义类是什么。All three classes define the following events, which behave similarly, regardless of the defining class.

像键盘和鼠标事件一样,触摸事件也是路由事件。Like keyboard and mouse events, the touch events are routed events. Preview 开头的事件是隧道事件,以 Touch 开头的事件是冒泡事件。The events that begin with Preview are tunneling events and the events that begin with Touch are bubbling events. 有关路由事件的详细信息,请参阅路由事件概述For more information about routed events, see Routed Events Overview. 处理这些事件时,可以通过调用 @no__t 0 或 GetIntermediateTouchPoints 方法来获取输入的相对于任何元素的位置。When you handle these events, you can get the position of the input, relative to any element, by calling the GetTouchPoint or GetIntermediateTouchPoints method.

为了理解触控事件之间的交互,请考虑以下这种情况:用户将一个手指放在元素上,在该元素中移动手指,然后将手指从该元素上移开。To understand the interaction among the touch events, consider the scenario where a user puts one finger on an element, moves the finger in the element, and then lifts the finger from the element. 下图显示了冒泡事件的执行(为简单起见,省略了隧道事件)。The following illustration shows the execution of the bubbling events (the tunneling events are omitted for simplicity).

触摸事件的序列。触摸事件The sequence of touch events. Touch events

下列内容描述了上图中的事件顺序。The following list describes the sequence of the events in the preceding illustration.

  1. 当用户将手指放在元素上时,将发生 @no__t 的事件一次。The TouchEnter event occurs one time when the user puts a finger on the element.

  2. @No__t 事件发生一次。The TouchDown event occurs one time.

  3. 当用户将手指移动到元素中时,会多次发生 TouchMove 事件。The TouchMove event occurs multiple times as the user moves the finger within the element.

  4. 当用户将手指从元素中抬起时,将发生 @no__t 的事件一次。The TouchUp event occurs one time when the user lifts the finger from the element.

  5. @No__t 事件发生一次。The TouchLeave event occurs one time.

当使用两根以上的手指时,每根手指都会发生事件。When more than two fingers are used, the events occur for each finger.

操作事件Manipulation Events

对于应用程序允许用户操纵对象的情况,@no__t 0 类定义操作事件。For cases where an application enables a user to manipulate an object, the UIElement class defines manipulation events. 与只是报告触摸位置的触摸事件不同,操作事件会报告可采用何种方式解释输入。Unlike the touch events that simply report the position of touch, the manipulation events report how the input can be interpreted. 有三种类型的操作:转换、扩展和旋转。There are three types of manipulations, translation, expansion, and rotation. 下列内容介绍了如何调用这三种类型的操作。The following list describes how to invoke the three types of manipulations.

  • 将一根手指放在对象上,并在触摸屏上拖动手指以调用转换操作。Put a finger on an object and move the finger across the touchscreen to invoke a translation manipulation. 此操作通常会移动对象。This usually moves the object.

  • 将两根手指放在物体上,并将手指相互靠拢或分开以调用扩展操作。Put two fingers on an object and move the fingers closer together or farther apart from one another to invoke an expansion manipulation. 此操作通常会调整对象的大小。This usually resizes the object.

  • 将两根手指放在对象上,并将一个手指围绕另一个手指旋转以调用旋转操作。Put two fingers on an object and rotate the fingers around each other to invoke a rotation manipulation. 此操作通常会旋转对象。This usually rotates the object.

多种类型的操作可以同时发生。More than one type of manipulation can occur simultaneously.

使对象响应操作时,可以让对象看起来具有惯性。When you cause objects to respond to manipulations, you can have the object appear to have inertia. 这样可以使对象模拟真实的世界。This can make your objects simulate the physical world. 例如,在桌子上推一本书时,如果你足够用力,书将在你松手后继续移动。For example, when you push a book across a table, if you push hard enough the book will continue to move after you release it. 利用 WPFWPF,可以通过在用户的手指松开对象后引发操作事件来模拟这种行为。WPFWPF enables you to simulate this behavior by raising manipulation events after the user's fingers releases the object.

有关如何创建使用户能够移动、调整大小和旋转对象的应用程序的信息,请参阅 [Walkthrough:正在创建您的第一个 Touch 应用程序 @ no__t。For information about how to create an application that enables the user to move, resize, and rotate an object, see Walkthrough: Creating Your First Touch Application.

@No__t-0 定义以下操作事件。The UIElement defines the following manipulation events.

默认情况下,@no__t 0 不会接收这些操作事件。By default, a UIElement does not receive these manipulation events. 若要在 @no__t 上接收操作事件,请将 @no__t 设置为 trueTo receive manipulation events on a UIElement, set UIElement.IsManipulationEnabled to true.

操作事件的执行路径The Execution Path of Manipulation Events

考虑用户“抛出”一个对象的情况。Consider a scenario where a user "throws" an object. 用户将手指放在对象上,将手指在触摸屏上移动一段短距离,然后在移动的同时抬起手指。The user puts a finger on the object, moves the finger across the touchscreen for a short distance, and then lifts the finger while it is moving. 此操作的结果是,该对象将在用户的手指下方移动,并在用户抬起手指后继续移动。The result of this is that the object will move under the user's finger and continue to move after the user lifts the finger.

下图显示了操作事件的执行路径和每个事件的重要信息。The following illustration shows the execution path of manipulation events and important information about each event.

操作事件的序列。操作事件The sequence of manipulation events. Manipulation events

下列内容描述了上图中的事件顺序。The following list describes the sequence of the events in the preceding illustration.

  1. 当用户将手指放在对象上时,将发生 ManipulationStarting 事件。The ManipulationStarting event occurs when the user places a finger on the object. 除此之外,此事件还允许您设置 ManipulationContainer 属性。Among other things, this event allows you to set the ManipulationContainer property. 在随后的事件中,操作的位置将与 @no__t 相关。In the subsequent events, the position of the manipulation will be relative to the ManipulationContainer. ManipulationStarting 以外的事件中,此属性是只读的,因此只能在 @no__t 1 事件中设置此属性。In events other than ManipulationStarting, this property is read-only, so the ManipulationStarting event is the only time that you can set this property.

  2. 接下来发生 ManipulationStarted 事件。The ManipulationStarted event occurs next. 此事件报告操作的原始位置。This event reports the origin of the manipulation.

  3. 当用户的手指在触摸屏上移动时,@no__t 的事件发生多次。The ManipulationDelta event occurs multiple times as a user's fingers move on a touchscreen. @No__t 类的 DeltaManipulation 属性报告操作是解释为移动、扩展还是转换。The DeltaManipulation property of the ManipulationDeltaEventArgs class reports whether the manipulation is interpreted as movement, expansion, or translation. 这是你执行操作对象的大部分工作的地方。This is where you perform most of the work of manipulating an object.

  4. 当用户的手指与对象失去联系时,将发生 ManipulationInertiaStarting 事件。The ManipulationInertiaStarting event occurs when the user's fingers lose contact with the object. 此事件使你可以指定操作在惯性期间的减速。This event enables you to specify the deceleration of the manipulations during inertia. 这样,选择时对象就可以模拟不同的物理空间或特性。This is so your object can emulate different physical spaces or attributes if you choose. 例如,假设应用程序有两个表示真实世界中的物品的对象,并且一个物品比另一个物品重。For example, suppose your application has two objects that represent items in the physical world, and one is heavier than the other. 你可以使较重的对象比较轻的对象减速更快。You can make the heavier object decelerate faster than the lighter object.

  5. 发生惯性时,@no__t 0 事件发生多次。The ManipulationDelta event occurs multiple times as inertia occurs. 请注意,当用户的手指在触摸屏上移动并且 WPFWPF 模拟惯性时,将发生此事件。Note that this event occurs when the user's fingers move across the touchscreen and when WPFWPF simulates inertia. 换句话说,在 @no__t 1 事件之前和之后发生 @no__t。In other words, ManipulationDelta occurs before and after the ManipulationInertiaStarting event. @No__t-0 属性报告惯性期间是否发生了 @no__t 1 事件,因此您可以检查该属性并执行不同的操作,具体取决于其值。The ManipulationDeltaEventArgs.IsInertial property reports whether the ManipulationDelta event occurs during inertia, so you can check that property and perform different actions, depending on its value.

  6. 当操作和任何惯性结束时,将发生 @no__t 0 事件。The ManipulationCompleted event occurs when the manipulation and any inertia ends. 也就是说,在所有 ManipulationDelta 事件发生后,将发生 @no__t 1 事件,指示操作已完成。That is, after all the ManipulationDelta events occur, the ManipulationCompleted event occurs to signal that the manipulation is complete.

@No__t 还定义 @no__t 1 事件。The UIElement also defines the ManipulationBoundaryFeedback event. 当 @no__t 事件中调用 ReportBoundaryFeedback 方法时发生此事件。This event occurs when the ReportBoundaryFeedback method is called in the ManipulationDelta event. @No__t-0 事件使应用程序或组件能够在对象达到边界时提供可视反馈。The ManipulationBoundaryFeedback event enables applications or components to provide visual feedback when an object hits a boundary. 例如,Window 类处理 @no__t 1 事件,以使窗口在遇到其边缘时轻微移动。For example, the Window class handles the ManipulationBoundaryFeedback event to cause the window to slightly move when its edge is encountered.

您可以取消操作,方法是对任何操作事件中的事件参数调用 Cancel 方法,ManipulationBoundaryFeedback 事件除外。You can cancel the manipulation by calling the Cancel method on the event arguments in any manipulation event except ManipulationBoundaryFeedback event. 调用 Cancel 时,将不再引发操作事件,并发生触控鼠标事件。When you call Cancel, the manipulation events are no longer raised and mouse events occur for touch. 下表描述了取消操作的时间与所发生的鼠标事件之间的关系。The following table describes the relationship between the time the manipulation is canceled and the mouse events that occur.

在其中调用取消的事件The event that Cancel is called in 针对已经发生的输入发生的鼠标事件The mouse events that occur for input that already occurred
ManipulationStartingManipulationStartedManipulationStarting and ManipulationStarted 鼠标按下事件。Mouse down events.
ManipulationDelta 鼠标按下和鼠标移动事件。Mouse down and mouse move events.
ManipulationInertiaStartingManipulationCompletedManipulationInertiaStarting and ManipulationCompleted 鼠标按下、鼠标移动和鼠标弹起事件。Mouse down, mouse move, and mouse up events.

请注意,如果在操作处于惯性中时调用 Cancel,则该方法将返回 false,并且输入不会引发鼠标事件。Note that if you call Cancel when the manipulation is in inertia, the method returns false and the input does not raise mouse events.

触摸事件和操作事件之间的关系The Relationship Between Touch and Manipulation Events

@No__t-0 总是可以接收触控事件。A UIElement can always receive touch events. 如果 IsManipulationEnabled 属性设置为 true,@no__t 则可以同时接收触控事件和操作事件。When the IsManipulationEnabled property is set to true, a UIElement can receive both touch and manipulation events. 如果未处理 @no__t 0 事件(即,@no__t 属性 false),则操作逻辑会将触摸屏捕获到元素,并生成操作事件。If the TouchDown event is not handled (that is, the Handled property is false), the manipulation logic captures the touch to the element and generates the manipulation events. 如果在 TouchDown 事件中将 @no__t 0 属性设置为 true,则操作逻辑不会生成操作事件。If the Handled property is set to true in the TouchDown event, the manipulation logic does not generate manipulation events. 下图显示了触摸事件和操作事件之间的关系。The following illustration shows the relationship between touch events and manipulation events.

触控事件和操作事件之间的关系触控和操作事件Relationship between touch and manipulation events Touch and manipulation events

下列内容描述了上图中所示的触摸事件和操作事件之间的关系。The following list describes the relationship between the touch and manipulation events that is shown in the preceding illustration.

焦点Focus

WPFWPF 中,有两个与焦点有关的主要概念:键盘焦点和逻辑焦点。There are two main concepts that pertain to focus in WPFWPF: keyboard focus and logical focus.

键盘焦点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. WPFWPF 中,具有键盘焦点的元素将 @no__t 设置为 trueIn WPFWPF, the element that has keyboard focus will have IsKeyboardFocused set to true. 静态 Keyboard 方法 @no__t 返回当前具有键盘焦点的元素。The static Keyboard method FocusedElement returns the element that currently has keyboard focus.

可以通过切换到元素或在某些元素上单击鼠标(如 TextBox)来获取键盘焦点。Keyboard focus can be obtained by tabbing to an element or by clicking the mouse on certain elements, such as a TextBox. 还可以通过对 @no__t 1 类使用 Focus 方法,以编程方式获取键盘焦点。Keyboard focus can also be obtained programmatically by using the Focus method on the Keyboard class. Focus 尝试给指定元素键盘焦点。Focus attempts to give the specified element keyboard focus. @No__t 返回的元素是当前具有键盘焦点的元素。The element returned by Focus is the element that currently has keyboard focus.

为了使元素获得键盘焦点,Focusable 属性和 @no__t 属性必须设置为trueIn order for an element to obtain keyboard focus the Focusable property and the IsVisible properties must be set to true. 某些类(如 Panel) @no__t 默认设置为 false。因此,如果希望该元素能够获得焦点,则可能必须将此属性设置为 trueSome 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.

下面的示例使用 Focus 将键盘焦点设置到 @no__t 1。The following example uses Focus to set keyboard focus on a Button. 在应用程序中设置初始焦点的建议位置是在 @no__t 0 事件处理程序中。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);
}
Private Sub OnLoaded(ByVal sender As Object, ByVal e As RoutedEventArgs)
    ' Sets keyboard focus on the first Button in the sample.
    Keyboard.Focus(firstButton)
End Sub

有关键盘焦点的详细信息,请参阅焦点概述For more information about keyboard focus, see Focus Overview.

逻辑焦点Logical Focus

逻辑焦点指的是焦点范围中的 @no__t 0。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.

焦点作用域是一个容器元素,用于跟踪其范围内的 @no__t 0。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.

可以通过将 @no__t 的附加属性设置为 可扩展应用程序标记语言 (XAML)Extensible Application Markup Language (XAML),将元素转换为焦点范围,方法是将第2个附加 @no__t 属性设置为 true,或在代码中通过使用 @no__t 方法设置附加属性。An element can be turned into a focus scope in 可扩展应用程序标记语言 (XAML)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.

下面的示例通过设置 @no__t 附加属性,将 @no__t 0 转换为焦点范围。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);
Dim focuseScope2 As New StackPanel()
FocusManager.SetIsFocusScope(focuseScope2, True)

默认情况下,默认值为 WPFWPF 中的类是 WindowMenuToolBar 和 @no__t。Classes in WPFWPF which are focus scopes by default are Window, Menu, ToolBar, and ContextMenu.

具有键盘焦点的元素还将对其所属的焦点范围具有逻辑焦点;因此,将焦点设置到 @no__t 类或基元素类上具有 Focus 方法的元素上时,将尝试为元素设置键盘焦点和逻辑焦点。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.

若要确定焦点范围中的焦点元素,请使用 GetFocusedElementTo determine the focused element in a focus scope, use GetFocusedElement. 若要更改焦点范围中的焦点元素,请使用 SetFocusedElementTo change the focused element for a focus scope, use SetFocusedElement.

有关逻辑焦点的详细信息,请参阅焦点概述For more information about logical focus, see Focus Overview.

鼠标位置Mouse Position

@No__t-0 输入 API 提供有关坐标空间的有用信息。The WPFWPF input API provides helpful information with regard to coordinate spaces. 例如,坐标 (0,0) 为左上角坐标,但该坐标是树中那一个元素的左上角坐标?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? 为避免混淆,在使用通过鼠标获取的坐标时,@no__t 输入 API 需要指定引用框架。To avoid confusion, the WPFWPF input API requires that you specify your frame of reference when you work with coordinates obtained through the mouse. @No__t-0 方法返回鼠标指针相对于指定元素的坐标。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. 输入系统公开可确定鼠标捕获状态的 Api,以及可强制将鼠标捕获到特定元素或清除鼠标捕获状态的 Api。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 Drag and Drop Overview.

命令Commands

使用命令,输入处理可以更多地在语义级别(而不是在设备输入级别)进行。Commands enable input handling at a more semantic level than device input. 命令是简单的指令,如 CutCopyPasteOpenCommands are simple directives, such as Cut, Copy, Paste, or Open. 命令可用于集中命令逻辑。Commands are useful for centralizing your command logic. 可以通过 Menu、@no__t 或键盘快捷方式访问同一命令。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.

@no__t 为 ICommand 的 @no__t 1 实现。RoutedCommand is the WPFWPF implementation of ICommand. 当执行 RoutedCommand 时,将在命令目标上引发 PreviewExecuted 和 @no__t 2 事件,此事件将通过元素树进行隧道和冒泡,如其他输入。When a RoutedCommand is executed, a PreviewExecuted and an Executed event are raised on the command target, which tunnel and bubble through the element tree like other input. 如果未设置命令目标,则具有键盘焦点的元素将成为命令目标。If a command target is not set, the element with keyboard focus will be the command target. 执行命令的逻辑附加到 CommandBindingThe logic that performs the command is attached to a CommandBinding. 如果 @no__t 0 事件对于该特定命令达到 CommandBinding,则会调用 CommandBinding 的 @no__t。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 Commanding Overview.

@no__t 提供了一种通用命令库,其中包含 ApplicationCommandsMediaCommandsComponentCommands、@no__t 和 @no__t,或者你可以定义自己的命令。WPFWPF provides a library of common commands which consists of ApplicationCommands, MediaCommands, ComponentCommands, NavigationCommands, and EditingCommands, or you can define your own.

下面的示例演示如何设置 MenuItem,以便在单击此项时,它将调用 TextBox 上的 Paste 命令,假定 @no__t 为3。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;

  // Setting the command target to the TextBox
  pasteMenuItem.CommandTarget = pasteTextBox;
' Creating the UI objects
Dim mainStackPanel As New StackPanel()
Dim pasteTextBox As New TextBox()
Dim stackPanelMenu As New Menu()
Dim pasteMenuItem As 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

有关 WPFWPF 中的命令的详细信息,请参阅命令概述For more information about commands in WPFWPF, see Commanding Overview.

输入系统和基元素The Input System and Base Elements

输入事件(例如 MouseKeyboardStylus 类定义的附加事件)由输入系统引发,并根据运行时的可视化树命中测试,注入到对象模型中的特定位置。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.

每个 MouseKeyboardStylus 定义为附加事件的事件也会由基元素类 UIElementContentElement 作为新的路由事件重新公开。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. 通常,使用 UIElementContentElement 上的路由事件处理这些与设备有关的输入事件更方便,因为可以在 XAMLXAML 和代码中使用更直观的事件处理程序语法。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 XAMLXAML and in code. 你可以选择处理发起进程的附加事件,但将会面临几个问题:附加事件可能会被基元素类处理标记为已处理,并且你需要使用访问器方法(而不是真正的事件语法)才能为附加事件附加处理程序。You could choose to handle the attached event that initiated the process instead, but you would face several issues: the attached event may be marked handled by the base element class handling, and you need to use accessor methods rather than true event syntax in order to attach handlers for attached events.

下一步What's Next

现在有多种方法来处理 WPFWPF 中的输入。You now have several techniques to handle input in WPFWPF. 你还应该对 WPFWPF 使用的各种类型的输入事件和路由事件机制有进一步的了解。You should also have an improved understanding of the various types of input events and the routed event mechanisms used by WPFWPF.

也可以获取更详细说明 WPFWPF 框架元素和事件路由的详细资源。Additional resources are available that explain WPFWPF framework elements and event routing in more detail. 有关详细信息,请参阅以下概述:命令概述焦点概述基元素概述WPF 中的树路由事件概述See the following overviews for more information, Commanding Overview, Focus Overview, Base Elements Overview, Trees in WPF, and Routed Events Overview.

请参阅See also