XAML 中的事件处理
创建 XAML UI 后,可添加代码来响应用户访问页面时发生的交互。 .NET MAUI 通过标准 .NET 事件通知应用程序发生了用户输入和交互。
本单元将介绍如何处理这些事件并执行用户预期的操作。
XAML 页面中的命名元素
事件处理代码经常需要引用页面上的特定控件及其属性。 可以为每个控件分配唯一名称。 为此,请使用 XAML 属性 x:Name
。 x:Name
属性具有两个作用:
它将专用字段添加到生成的代码隐藏文件中,该文件会映射到此元素。 在代码中使用该字段与视觉元素交互,以便设置运行时属性和处理事件。
XAML 通过此名称获知该元素。 可以从同一 XAML 文件中定义的其他元素来引用这些元素。
为元素命名时,不能使用任意字符串。 分配给 x:Name
属性的值用于在代码中创建字段。 名称必须符合变量的命名约定。 该名称还必须是唯一的,因为它会被编入代码隐藏定义。
为元素提供名称后,可以在代码隐藏文件中与该元素进行交互。 以下 XAML 片段定义 Label
控件。 它被命名为 CounterLabel(此示例摘自 .NET MAUI 模板生成的默认应用):
<Label Text="Current count: 0"
...
x:Name="CounterLabel"
... />
在此页面的代码隐藏中,可通过 CounterLabel
字段引用此控件,并修改其属性:
count++;
CounterLabel.Text = $"Current count: {count}";
重要
在运行页面的 InitializeComponent
方法之前,不会初始化该字段。 此方法是 XAML 分析和对象实例化过程的一部分。 在此调用后,放置与使用 XAML 定义的元素交互的任何代码。 此规则的例外情况是 ContentPage
类本身。 在执行 InitializeComponent
方法之前,可以访问此类的所有属性。 但是,如果使用 XAML 为此类设置任何属性,则这些属性值将覆盖执行 InitializeComponent
之前可能设置的任何值。
使用属性来连接事件
许多控件公开与这些控件可以响应的事件相对应的属性,例如按钮的 Clicked
事件。 不同控件支持不同事件集。 例如,Button
控件可以响应 Clicked
、Pressed
和 Released
事件,而 Entry
控件响应 TextChanged
等事件。 可以在页面的 XAML 标记中初始化事件属性,并指定触发事件时要运行的方法的名称。 事件方法必须满足以下签名要求:
- 它不能返回值;方法必须为
void
。 - 它必须采用两个参数;一个是
object
引用,指示触发事件的对象(称为发送方),另一个是EventArgs
参数,包含发送方传递给事件处理程序的任何自变量。 - 事件处理程序应为
private
。 没有强制要求这一点,但如果将事件处理程序公开,外界就可进行访问它,而且触发的预期事件以外的操作可以调用它。 - 如果需要运行异步操作,事件处理程序可以是
async
。
下面的示例展示 .NET MAUI 模板中示例应用按钮的 Clicked
事件处理程序的定义。 方法名称遵循标准约定;On 后跟控件的名称(按钮名为 Counter)和事件的名称 (Clicked)。 此约定不会强制执行,但是很好的做法:
private void OnCounterClicked(object sender, EventArgs e)
{
...
}
分离关注点
连接使用 XAML 的事件很方便,但这会将控件行为与 UI 定义混合在一起。 许多开发人员倾向于将这些元素进行区分,并将代码隐藏中的所有事件处理程序订阅到命名元素。 这样更容易看到连接的内容以及行为映射到的位置。 这种方法还可使得更难在未意识到的情况下因移除 XAML 中的处理程序而意外破坏代码。 编译程序不会捕获已移除的处理程序,并且只有在代码未正确执行该行为时才会显示存在问题。
无论是选择使用 XAML 还是代码来连接事件处理程序,都取决于个人选择。
若要在代码中连接事件处理程序,请使用 +=
运算符订阅事件。 调用 InitializeComponent
后,通常会在页面的构造函数中执行此操作:
public partial class MainPage : ContentPage, IPage
{
public MainPage()
{
InitializeComponent();
Counter.Clicked += OnCounterClicked;
}
...
private void OnCounterClicked(object sender, EventArgs e)
{
...
}
}
注意
可使用此方法订阅同一事件的多个事件处理方法。 每个事件处理方法都会在事件发生时运行,但不应假定这些方法将按任何特定顺序执行,因此不要在它们之间引入任何依赖项。
同样,稍后在应用程序中,可使用 -=
运算符从事件中取消订阅事件处理程序来移除它:
Counter.Clicked -= OnCounterClicked;