MSDN Library
信息
您所需的主题如下所示。但此主题未包含在此库中。

Windows Phone 8 的事件

2014/6/18

适用于:Windows Phone 8 和 Windows Phone Silverlight 8.1 | Windows Phone OS 7.1

本主题介绍事件的编程概念、事件概念如何在 Windows Phone 中发挥作用及其编程模型。Windows Phone 事件与公共语言运行时 (CLR) 和 .NET Framework 对于事件概念的定义在本质上是相同的。与 WPF 类似,您可以将事件的处理程序分配为 XAML 中 UI 元素的声明的一部分,也可以使用语言特定的语法在代码中添加处理程序。Windows Phone 支持路由事件的概念,通过路由事件这一功能,某些输入事件和数据事件可以由除引发事件的对象之外的其他对象进行处理。当组合控件模板或集中处理应用页的事件逻辑时,路由事件特别有用。

本主题包括以下部分。

事件是对象发送的消息,用于指示发生了操作。操作可能是由用户交互(例如触摸屏幕)引起的,也可能是由某个类的内部逻辑触发的。引发事件的对象称为事件发送方。捕获事件并对其作出响应的对象叫做事件接收方。总体而言,事件的作用是交流某个对象在运行时的时间特定的、相对轻量的信息,并可能将该信息传送到应用中的其他对象。

Windows Phone 事件

一般而言,Windows Phone 事件是 CLR 事件,因此是可以使用托管代码来处理的事件。如果您已知道如何使用基本 CLR 事件,则对所涉及的某些概念就已经成竹在胸了。但是,您并不一定需要很透彻地了解有关 CLR 事件模型的内容,就能够执行某些基本任务,如附加处理程序。

由于基于 Windows Phone 的典型应用的 UI 在标记 (XAML) 中定义,将 UI 事件从标记元素连接到运行时代码实体的某些原则类似于其他 Web 技术(如 ASP.NET)或类似于使用 HTML DOM。在 Windows Phone 中,为用 XAML 定义的 UI 提供运行时逻辑的代码经常被称为代码隐藏或代码隐藏文件。在 Visual Studio 解决方案视图中,此关系用图形方式显示,其中的代码隐藏文件表示为独立嵌套文件而不是它所指的 XAML 页面。

除了在其自己的运行时对象模型中操作的 CLR 事件,Windows Phone 还具有一些事件,这些事件可在 HTML 级别上调用基于脚本的处理程序,如 OnError。这些事件由针对 HTML DOM 中的插件实例运行的任何脚本公开,并可由此脚本进行处理。作为应用的一般事件模型,最先应使用 HTML 脚本进行处理;而且如果您在 HTML 中处理事件,这些事件不应被传递给托管 API。

由于 Windows Phone 属于 UI 技术,因此,您要执行的最常见任务之一是捕获用户对 UI 的输入。例如,UI 可能具有一个按钮,用户必须点击此按钮才能提交信息或更改应用的状态。

通常可以通过生成 XAML 为基于 Windows Phone 的应用定义 UI。此 XAML 可以是来自诸如 Blend for Visual Studio 的设计器的输出,或是来自诸如 Windows Phone 的较大 IDE 中的设计图面的输出。也可以在纯文本编辑器或第三方 XAML 编辑器中编写 XAML。作为生成该 XAML 的一部分,您可以在定义用于描述该 UI 元素的所有其他属性的同时,为各个 UI 元素连结事件处理程序。

如果您使用 Windows Phone,则可以使用设计功能,这样,要从 XAML 中连结事件处理程序,然后在代码隐藏中定义它们,就非常简单了。这包括为处理程序提供自动命名方案。

您还可以使用 Windows Phone 的 .NET Framework 类库文档来查找特定事件并确定其委托。您编写的处理程序必须与该委托签名兼容。对于上文所示的示例,最匹配的委托为 RoutedEventHandler

说明注意:

调用 Windows Phone 事件处理程序函数时不能使用参数值(即使是空参数值也不例外),这一点与 HTML DOM 中的事件处理程序语法明显不同。XAML 中的属性值只是引用处理程序名称,而其他机制(例如,处理程序的预期输入参数)负责传递信息。

对于在 XAML 中作为 UI 并声明的对象,必须在充当 XAML 页的代码隐藏的分部类中定义事件处理程序代码。

分部类中的事件处理程序根据由该特定事件使用的 CLR 委托编写为方法。事件处理程序方法可以是公共方法,也可以具有私有访问级别。私有访问将发挥作用,因为由 XAML 创建的处理程序和实例最终将通过代码生成来进行联接。一般建议是不要让事件处理程序方法在类中成为公共方法。

您为托管的 Windows Phone 事件编写的任何处理程序都可以访问两个值,这两个值对于调用处理程序的每种情况都可以用作输入。第一个这样的值是 sender,该值是对于在其中附加处理程序的对象的引用。sender 参数被类型化为基本 Object 类型。Windows Phone 事件处理中的一个常用方法是将 sender 强制转换为更精确的类型。如果希望对 sender 对象本身检查或更改状态,则此方法很有用。根据您自己的应用设计,基于处理程序附加到的位置或其他设计细节,您需要一种可以将 sender 安全地强制转换为类型。

第二个值是事件数据,它通常作为 e 参数出现在签名中。根据 CLR 事件模型,所有事件均发送某种事件数据,并且这些数据将作为某个类的实例被捕获,而该类将继承 EventArgs(或为 EventArgs 本身)。您可以通过查找为您正在处理的特定事件分配的委托的 e 参数,然后使用 Visual Studio 中的 Intellisense 或 Windows Phone 的 .NET Framework 类库,查找事件数据的哪些属性是可用的。一些 Windows Phone 事件使用 EventHandler<TEventArgs> 委托或其他泛型处理程序类型。大多数情况下,事件定义限制使用具有特定 EventArgs 派生事件数据类的泛型。随后应编写处理程序方法,就像它将 EventArgs 派生事件数据类直接用作第二个参数一样。

对于某些事件,EventArgs 派生类中的事件数据与知道事件被引发同样重要。对于输入事件尤其如此。对于键盘事件,按下键盘上的键引发相同的 KeyUpKeyDown 事件。为了确定按下了哪个键,必须访问可用于事件处理程序的 KeyEventArgs

XAML 并不是向对象分配事件处理程序的唯一方式。若要在托管代码中将事件处理程序添加到任何给定对象(包括添加到甚至在 XAML 中不可用的对象),可以使用特定于 CLR 语言的语法来添加事件处理程序。

在 C# 中,语法中使用 += 运算符。您通过声明使用事件处理程序方法名称的新委托来实例化处理程序。

如果您使用代码将事件处理程序添加到在运行时 UI 中显示的对象,则 Windows Phone 的通用做法是添加此类处理程序以响应对象生存期事件或回调(例如,LoadedOnApplyTemplate),以便相关对象上的事件处理程序准备好处理在运行时用户启动的事件。

Visual Basic 语法的另一个选项是对于事件处理程序使用 Handles 关键字。这种方法适合以下这类情况:加载时在对象上预计存在处理程序,且处理程序在整个对象生存期中一直存在。如果对于在 XAML 中定义的对象使用 Handles,则要求您提供 Name / x:Name。此名称成为 Handles 语法的 Instance.Event 部分所需的实例限定符。在此情况下,您不需要基于对象生存期的事件处理程序,即可启动附加其他事件处理程序的过程;当您编译 XAML 页时,将创建 Handles 连接。

Sub textBlock1_MouseEnter(ByVal sender As Object, ByVal e As MouseEventArgs) Handles textBlock1.MouseEnter
'....
End Sub
Sub textBlock1_MouseLeave(ByVal sender As Object, ByVal e As MouseEventArgs) Handles textBlock1.MouseLeave
'....
End Sub
说明注意:

Visual Studio 及其 XAML 设计图面通常提升实例处理方法而不是 Handles 关键字。这是因为在 XAML 中建立事件处理程序连结是典型的 Windows Phone 设计人员-开发人员工作流的一部分,而 Handles 关键字方法与在 XAML 中连结事件处理程序的方法不兼容。

对于在基类中定义的并在支持用户交互和输入的大多数 UI 元素中存在的若干输入事件,Windows Phone 支持路由事件的概念。以下是作为路由事件的输入事件的列表:

路由事件是在对象树中可能从某个子对象传递(路由)到其每个后续父对象的事件。所涉及的对象树与 UI 的 XAML 结构近似,该树的根成为 XAML 中的根元素。真正的对象树可能与 XAML 稍有不同,因为对象树不包括属性元素标记之类的 XAML 语言功能。一般来说,您可以将路由事件想像为从引发事件的 XAML 对象元素子集“冒泡”到包含这些子集的父对象元素。出现的事件及其事件数据一直冒泡并报告给沿着事件路由的对象,直到达到根事件。(如果您曾经用过某些 Web 技术,如 DHTML,则您可能已经熟悉了“冒泡”概念。)

说明注意:

XAML 支持类似的“隧道”路由策略,因此,页/对象树的根首先有机会来处理路由事件,然后,该事件通过“隧道”沿着对象树向下传递到其事件源。Windows Phone 不使用“隧道”传递路由事件。Windows Phone 中的事件要么遵循"冒泡"路由策略(也称为路由事件),要么根本不路由。在 wphone 和 XAML 之间的路由事件行为中还存在其他 API 级别的差异。

RoutedEventArgs 的 OriginalSource 属性

当事件向上冒泡事件路由时,sender 不再是与事件引发对象相同的对象。相反,sender 是在其中附加正在调用的处理程序的对象。在许多情况下,sender 不是您感兴趣的对象,并且您更希望了解当按下键盘键时哪个对象具有焦点等此类信息。对于此类情况,OriginalSource 属性的值是您感兴趣的对象。

在路由的所有点上,OriginalSource 都报告引发事件的原始对象,而不是附加处理程序的位置。关于上述方式在哪些情况下有用,请考虑这样一个应用:在该应用中,您希望某些键组合成为“热键”或快捷键,而不考虑哪个控件当前具有键盘焦点并启动了事件。就对象树而言,具有焦点的对象可能嵌套在列表框中包括某些项的列表内,也可能是整个用户界面中的众多对象之一。如果必须将处理程序附加到应用中每个可能获得焦点的对象才能检测到快捷键,则这很明显是不切实际的。但是,因为键盘事件正在冒泡路由事件,所以,该事件最终会在其路由中到达根对象。因此,您通常可以在根对象上附加单个 KeyDown 处理程序,并依赖于 KeyDown 事件最终冒泡到根对象的行为。然后,处理程序可以确定该键是否为预期快捷键操作的有效组合,或者是否不需要执行操作。

提示提示:

如果您正在创建模板化的控件,充分发挥输入冒泡的优势对于您尤其有用。具有模板的所有控件都可以由其使用者应用新模板,因此,可能会消除在默认模板 XAML 中声明的任何事件处理。通过附加处理程序作为类定义中的 OnApplyTemplate 重写的一部分,然后捕获向上冒泡到该控件的根的输入事件,您仍可以提供控件级别的事件处理。

Handled 属性

特定路由事件的多个事件数据类包含一个名为 Handled 的属性。有关示例,请参见 MouseButtonEventArgs.HandledKeyEventArgs.HandledDragEventArgs.HandledValidationErrorEventArgs.HandledHandled 是一个可设置的布尔值属性。

Handled 属性设置为 true 会影响 Windows Phone 中的事件系统。当您在事件数据中将该值设置为 true 时,将对大多数事件处理程序停止路由;事件不会继续路由来向其他附加的处理程序通知该特定的事件。“已处理”作为一个操作在事件上下文中意味着什么以及应用如何响应,这全取决于您。但是,当您选择在事件处理程序中设置 Handled 时,应谨记 Windows Phone 事件系统的这一行为。

并非所有路由事件都可用这种方法取消。GotFocusLostFocusMouseMove 将始终一直路由到根目录,其事件数据类没有可影响该行为的 Handled 属性。因此,针对这些事件检查 OriginalSource 值通常是一个好主意,可确保您不处理事件,也不对事件的含义以及输入事件源自 UI 布局中的哪个位置进行不正确的假设。

说明注意:

XAML 中也存在路由事件的 Handled 属性概念。在 XAML 中,所有路由事件数据类上都存在 Handled 属性;在 Windows Phone 中,只有具有其自己的 Handled 属性的特定事件数据类可用来取消相关事件的路由。

可视化树外的路由事件

Windows Phone 中的某些对象涉及与主要可视化树的关系,主要可视化树在概念上类似在主要可视化元素上重叠。这些对象不是将所有树元素连接到可视根的常见父-子关系的一部分。任何显示的 Popup 就属于这种情况。如果您要处理来自 Popup 的路由事件,则应将处理程序放置于 Popup 内的特定 UI 元素上(而非 Popup 元素本身上)。不应依赖于为 Popup 内容执行的任何合成内的路由。这是因为对路由事件的事件路由仅适用于主可视化树。Popup 不视为子一级 UI 元素的父级,并且永远不接收路由的鼠标事件,即使正在尝试使用 Popup 默认背景这样的内容作为点击区域。

特定的现有 Windows Phone 控件有时在内部将此 Handled 概念用于输入事件。这可能会给用户留下代码中某个输入事件永远不会发生的印象。例如,Button 类包括的逻辑特意处理常见的输入事件 MouseLeftButtonDown。.NET Framework 库中特定控件类的参考主题通常会记下由该类实现的事件处理行为。在某些情况下,可以通过重写 OnEvent 方法在子类中更改或追加此行为。例如,您可以通过重写 TextBox.OnKeyDown 更改 TextBox 派生类响应键输入的方式。

为已处理的路由事件注册处理程序

如前面所述,将 Handled 设置为 true 可防止大多数处理程序执行操作。API AddHandler 提供了一种方法,通过该方法可以附加始终为路由调用的处理程序,即使路由中某个早期的其他处理程序已将 Handled 设置为 true。如果您正在使用的控件已在其内部合成中或针对控件特定的逻辑处理了该事件,但您仍然希望在控件实例或路由中的更高级别响应该事件,则这种方法很有用。然而,使用此方法时应务必小心,因为它可能与 Handled 的目的背道而驰,并可能违反控件的目标用途或对象模型。

有关更多信息(包括用法示例),请参见 AddHandler

Windows Phone 坚持只允许某些操作在处理用户启动的事件的处理程序的上下文中执行。以下是此类操作的列表:

Windows Phone 用户启动的事件包括鼠标事件(如 MouseLeftButtonDown)以及键盘事件(如 KeyDown)。基于此类事件的控件的事件也被视为用户启动的事件。

应在事件处理程序内尽快调用需要用户启动的 API 调用。这是因为 Windows Phone 用户启动概念还要求在事件发生后的一定时间长度内进行调用。在 Windows Phone 中,此时间长度大约为一秒。

在某些情况下,您可能希望在应用生存期中移除事件处理程序。若要移除事件处理程序,请使用特定于 CLR 语言的语法。在 C# 中,使用 -= 运算符。在 Visual Basic 中,使用 RemoveHandler 函数。任一种情况下,您都需要引用事件处理程序方法名。

下面的代码演示如何从目标对象 textBlock1 中删除名为 textBlocks_MouseEnter 的事件处理程序。

void Cleanup()
{
    textBlock1.MouseEnter -= textBlocks_MouseEnter;
}

如果事件是通过 XAML 属性添加的,则也可以移除处理程序。如果您为在其中附加处理程序的元素提供了 Name 值,则这一点实现起来更为容易,因为该元素稍后为代码提供了对象引用;不过,您还可以在对象树中导航以查找所需的对象引用(如果您必须这么做)。

在 Windows Phone 中,只有少数 UI 元素支持命令。命令在其基本实现中使用与输入相关的路由事件,并支持通过调用单个命令处理程序处理相关的 UI 输入(特定的鼠标操作、特定的快捷键)。如果对 UI 元素可使用命令,请考虑用其命令 API 来代替任何单独的输入事件。有关更多信息,请参见下列主题之一:

ButtonBase.Command

Hyperlink.Command

显示:
© 2016 Microsoft