触发器

Browse sample. 浏览示例

.NET Multi-platform App UI (.NET MAUI) 触发器允许你在 XAML 中以声明方式表达操作,这些操作会根据事件或数据更改来更改控件的外观。 此外,状态触发器是一组专门的触发器,定义了何时应该应用 VisualState

可以将触发器直接分配到控件的 Triggers 集合,或将其添加到页面级别或应用级别的资源词典中,以应用到多个控件。

属性触发器

Trigger 表示在指定属性满足指定条件时应用属性值或执行操作的触发器。

以下示例展示了在获得焦点时更改 Entry 背景颜色的 Trigger

<Entry Placeholder="Enter name">
    <Entry.Triggers>
        <Trigger TargetType="Entry"
                 Property="IsFocused"
                 Value="True">
            <Setter Property="BackgroundColor"
                    Value="Yellow" />
            <!-- Multiple Setter elements are allowed -->
        </Trigger>
    </Entry.Triggers>
</Entry>

触发器的声明指定以下内容:

  • TargetType - 触发器应用到的控件类型。
  • Property - 受监视的控件上的属性。
  • Value - 当此值针对受监视的属性出现时,将导致触发器被激活。
  • Setter - 满足触发器条件时应用的 Setter 元素集合。

此外,可以指定可选的 EnterActionsExitActions 集合。 有关详细信息,请参阅 EnterActions 和 ExitActions

使用样式应用触发器

还可将触发器添加到控件、页面或应用程序 ResourceDictionary 中的 Style 声明。 以下示例声明页面上所有 Entry 控件的隐式样式:

<ContentPage.Resources>
    <Style TargetType="Entry">
        <Style.Triggers>
            <Trigger TargetType="Entry"
                     Property="IsFocused"
                     Value="True">
                <Setter Property="BackgroundColor"
                        Value="Yellow" />
                <!-- Multiple Setter elements are allowed -->
            </Trigger>
        </Style.Triggers>
    </Style>
</ContentPage.Resources>

数据触发器

DataTrigger 表示在绑定数据满足指定条件时,应用属性值或执行操作的触发器。 Binding 标记扩展用于指定条件的监视活动。

以下示例演示了一个当 Entry 为空时禁用 ButtonDataTrigger

<Entry x:Name="entry"
       Text=""
       Placeholder="Enter text" />
<Button Text="Save">
    <Button.Triggers>
        <DataTrigger TargetType="Button"
                     Binding="{Binding Source={x:Reference entry},
                                       Path=Text.Length}"
                     Value="0">
            <Setter Property="IsEnabled"
                    Value="False" />
            <!-- Multiple Setter elements are allowed -->
        </DataTrigger>
    </Button.Triggers>
</Button>

在此示例中,Entry 的长度为零时将激活触发器。

提示

评估 Path=Text.Length 时,始终为目标属性(例如 Text="")提供默认值,因为若非如此,它将为 null,并且触发器不会像预期那样工作。

此外,可以指定可选的 EnterActionsExitActions 集合。 有关详细信息,请参阅 EnterActions 和 ExitActions

事件触发器

EventTrigger 表示应用一组操作以响应一个事件的触发器。 与 Trigger 不同,EventTrigger 没有状态终止的概念,因此若不再符合引发事件的条件,相应操作也不会撤消。

EventTrigger 只需要设置 Event 属性:

<EventTrigger Event="TextChanged">
    <local:NumericValidationTriggerAction />
</EventTrigger>

在此示例中,不存在 Setter 元素。 而是存在一个 NumericalValidationTriggerAction 对象。

注意

事件触发器不支持 EnterActionsExitActions

触发器操作实现必须:

  • 实现泛型 TriggerAction<T> 类,并且泛型参数对应于触发器将应用到的控件类型。 可以使用 VisualElement 等类写入适用于多种控件的触发器操作,或指定 Entry 等控件类型。
  • 重写 Invoke 方法。 在发生触发器事件时,此方法会被调用。
  • 声明触发器时,可选择公开能在 XAML 中设置的属性。

下面的示例展示了 NumericValidationTriggerAction 类:

public class NumericValidationTriggerAction : TriggerAction<Entry>
{
    protected override void Invoke(Entry entry)
    {
        double result;
        bool isValid = Double.TryParse(entry.Text, out result);
        entry.TextColor = isValid ? Colors.Black : Colors.Red;
    }
}

警告

ResourceDictionary 中共享触发器时要谨慎。 由于可在控件之间共享同一个实例,因此配置过一次的任何状态都会应用到所有这些控件。

多触发器

MultiTrigger 表示一个触发器,它会在一组条件得到满足时应用属性值或执行操作。 应用 Setter 对象前,必须满足所有条件。

以下示例演示绑定到两个 Entry 对象的 MultiTrigger

<Entry x:Name="email"
       Text="" />
<Entry x:Name="phone"
       Text="" />
<Button Text="Save">
    <Button.Triggers>
        <MultiTrigger TargetType="Button">
            <MultiTrigger.Conditions>
                <BindingCondition Binding="{Binding Source={x:Reference email},
                                            Path=Text.Length}"
                                  Value="0" />
                <BindingCondition Binding="{Binding Source={x:Reference phone},
                                            Path=Text.Length}"
                                  Value="0" />
            </MultiTrigger.Conditions>
            <Setter Property="IsEnabled" Value="False" />
            <!-- multiple Setter elements are allowed -->
        </MultiTrigger>
    </Button.Triggers>
</Button>

此外,MultiTrigger.Conditions 集合还可以包含 PropertyCondition 对象:

<PropertyCondition Property="Text"
                   Value="OK" />

EnterActions 和 ExitActions

通过指定 EnterActionsExitActions 集合,并创建 TriggerAction<T> 实现,是触发发生时实现更改的替代方法。

类型为 IList<TriggerAction>EnterActions 集合用于定义在满足触发条件时将调用的集合。 类型为 IList<TriggerAction>ExitActions 集合用于定义在不再满足触发条件后将调用的集合。

注意

EventTrigger 类将忽略 EnterActionsExitActions 集合中定义的 TriggerAction 对象。

以下示例展示了指定 EnterActionExitAction 的属性触发器:

<Entry Placeholder="Enter job title">
    <Entry.Triggers>
        <Trigger TargetType="Entry"
                 Property="Entry.IsFocused"
                 Value="True">
            <Trigger.EnterActions>
                <local:FadeTriggerAction StartsFrom="0" />
            </Trigger.EnterActions>

            <Trigger.ExitActions>
                <local:FadeTriggerAction StartsFrom="1" />
            </Trigger.ExitActions>
        </Trigger>
    </Entry.Triggers>
</Entry>

触发器操作实现必须:

  • 实现泛型 TriggerAction<T> 类,并且泛型参数对应于触发器将应用到的控件类型。 可以使用 VisualElement 等类写入适用于多种控件的触发器操作,或指定 Entry 等控件类型。
  • 重写 Invoke 方法。 在发生触发器事件时,此方法会被调用。
  • 声明触发器时,可选择公开能在 XAML 中设置的属性。

下面的示例展示了 FadeTriggerAction 类:

public class FadeTriggerAction : TriggerAction<VisualElement>
{
    public int StartsFrom { get; set; }

    protected override void Invoke(VisualElement sender)
    {
        sender.Animate("FadeTriggerAction", new Animation((d) =>
        {
            var val = StartsFrom == 1 ? d : 1 - d;
            sender.BackgroundColor = Color.FromRgb(1, val, 1);
        }),
        length: 1000, // milliseconds
        easing: Easing.Linear);
    }
}

注意

可以在触发器中同时提供 EnterActionsExitActionsSetter 对象,但注意,Setter 对象将立即调用(不会等待 EnterActionExitAction 完成)。

状态触发器

状态触发器是一组专门的触发器,它们定义了在哪些条件下应该应用 VisualState

状态触发器添加到 VisualStateStateTriggers 集合。 此集合可以包含一个或多个状态触发器。 当此集合中的任何状态触发器处于活动状态时,便会应用 VisualState

使用状态触发器来控制视觉状态时,.NET MAUI 使用以下优先规则来确定哪个触发器(以及相应的 VisualState)将处于活动状态:

  1. 任何派生自 StateTriggerBase 的触发器。
  2. 因满足 MinWindowWidth 条件而激活的 AdaptiveTrigger
  3. 因满足 MinWindowHeight 条件而激活的 AdaptiveTrigger

如果多个触发器同时处于活动状态(例如,两个自定义触发器),则标记中声明的第一个触发器优先。

注意

状态触发器可以在 Style 中设置,也可以直接对元素设置。

有关视觉状态的详细信息,请参阅视觉状态

状态触发器

StateTrigger 类派生自 StateTriggerBase 类,包含 IsActive 可绑定属性。 当 IsActive 属性值更改时,StateTrigger 触发 VisualState 更改。

StateTriggerBase 类是所有状态触发器的基类,包含 IsActive 属性和 IsActiveChanged 事件。 只要 VisualState 更改,就会触发此事件。 此外,StateTriggerBase 类包含可重写的 OnAttachedOnDetached 方法。

重要

StateTrigger.IsActive 可绑定属性隐藏继承的 StateTriggerBase.IsActive 属性。

下面的 XAML 示例展示了包含 StateTrigger 对象的 Style

<Style TargetType="Grid">
    <Setter Property="VisualStateManager.VisualStateGroups">
        <VisualStateGroupList>
            <VisualStateGroup>
                <VisualState x:Name="Checked">
                    <VisualState.StateTriggers>
                        <StateTrigger IsActive="{Binding IsToggled}"
                                      IsActiveChanged="OnCheckedStateIsActiveChanged" />
                    </VisualState.StateTriggers>
                    <VisualState.Setters>
                        <Setter Property="BackgroundColor"
                                Value="Black" />
                    </VisualState.Setters>
                </VisualState>
                <VisualState x:Name="Unchecked">
                    <VisualState.StateTriggers>
                        <StateTrigger IsActive="{Binding IsToggled, Converter={StaticResource inverseBooleanConverter}}"
                                      IsActiveChanged="OnUncheckedStateIsActiveChanged" />
                    </VisualState.StateTriggers>
                    <VisualState.Setters>
                        <Setter Property="BackgroundColor"
                                Value="White" />
                    </VisualState.Setters>
                </VisualState>
            </VisualStateGroup>
        </VisualStateGroupList>
    </Setter>
</Style>

在此示例中,隐式 StyleGrid 对象为目标。 当绑定对象的 IsToggled 属性为 true 时,Grid 的背景色设置为黑色。 当绑定对象的 IsToggled 属性变成 false 时,VisualState 更改触发,且 Grid 的背景色变成白色。

此外,每次只要 VisualState 发生更改,就会引发 VisualStateIsActiveChanged 事件。 每个 VisualState 都注册此事件的事件处理程序:

void OnCheckedStateIsActiveChanged(object sender, EventArgs e)
{
    StateTriggerBase stateTrigger = sender as StateTriggerBase;
    Console.WriteLine($"Checked state active: {stateTrigger.IsActive}");
}

void OnUncheckedStateIsActiveChanged(object sender, EventArgs e)
{
    StateTriggerBase stateTrigger = sender as StateTriggerBase;
    Console.WriteLine($"Unchecked state active: {stateTrigger.IsActive}");
}

在此示例中,当引发 IsActiveChanged 事件的处理程序时,处理程序输出消息会指明 VisualState 是否处于活动状态。 例如,当视觉对象状态从 Checked 更改为 Unchecked 时,以下消息输出到控制台窗口中:

Checked state active: False
Unchecked state active: True

注意

可以通过以下方法创建自定义状态触发器:从 StateTriggerBase 类派生,并重写 OnAttachedOnDetached 方法来执行任何所需注册和清理。

自适应触发器

当窗口为指定高度或宽度时,AdaptiveTrigger 触发 VisualState 更改。 此触发器有以下两个可绑定属性:

注意

由于 AdaptiveTrigger 派生自 StateTriggerBase 类,因此可以将事件处理程序附加到 IsActiveChanged 事件。

下面的 XAML 示例展示了包含 AdaptiveTrigger 对象的 Style

<Style TargetType="StackLayout">
    <Setter Property="VisualStateManager.VisualStateGroups">
        <VisualStateGroupList>
            <VisualStateGroup>
                <VisualState x:Name="Vertical">
                    <VisualState.StateTriggers>
                        <AdaptiveTrigger MinWindowWidth="0" />
                    </VisualState.StateTriggers>
                    <VisualState.Setters>
                        <Setter Property="Orientation"
                                Value="Vertical" />
                    </VisualState.Setters>
                </VisualState>
                <VisualState x:Name="Horizontal">
                    <VisualState.StateTriggers>
                        <AdaptiveTrigger MinWindowWidth="800" />
                    </VisualState.StateTriggers>
                    <VisualState.Setters>
                        <Setter Property="Orientation"
                                Value="Horizontal" />
                    </VisualState.Setters>
                </VisualState>
            </VisualStateGroup>
        </VisualStateGroupList>
    </Setter>
</Style>

在此示例中,隐式 StyleStackLayout 对象为目标。 当窗口宽度介于 0 到 800 个设备无关单位之间时,应用 StyleStackLayout 对象采用垂直方向。 当窗口宽度为 >= 800 个与设备无关的单位时,将触发 VisualState 更改,并且 StackLayout 方向更改为水平。

MinWindowHeightMinWindowWidth 属性可以单独使用,也可以结合使用。 下面的 XAML 示例展示了如何设置这两个属性:

<AdaptiveTrigger MinWindowWidth="800"
                 MinWindowHeight="1200"/>

在此示例中,AdaptiveTrigger 指示当前窗口宽度为 >= 800 个与设备无关的单位,且当前窗口高度为 >= 1200 个与设备无关的单位时,将应用相应的 VisualState

比较状态触发器

当属性等于特定值时,CompareStateTrigger 触发 VisualState 更改。 此触发器有以下两个可绑定属性:

  • 类型为 objectProperty,指明触发器所比较的属性。
  • 类型为 objectValue,指明触发应用 VisualState 的值。

注意

由于 CompareStateTrigger 派生自 StateTriggerBase 类,因此可以将事件处理程序附加到 IsActiveChanged 事件。

下面的 XAML 示例展示了包含 CompareStateTrigger 对象的 Style

<Style TargetType="Grid">
    <Setter Property="VisualStateManager.VisualStateGroups">
        <VisualStateGroupList>
            <VisualStateGroup>
                <VisualState x:Name="Checked">
                    <VisualState.StateTriggers>
                        <CompareStateTrigger Property="{Binding Source={x:Reference checkBox}, Path=IsChecked}"
                                             Value="True" />
                    </VisualState.StateTriggers>
                    <VisualState.Setters>
                        <Setter Property="BackgroundColor"
                                Value="Black" />
                    </VisualState.Setters>
                </VisualState>
                <VisualState x:Name="Unchecked">
                    <VisualState.StateTriggers>
                        <CompareStateTrigger Property="{Binding Source={x:Reference checkBox}, Path=IsChecked}"
                                             Value="False" />
                    </VisualState.StateTriggers>
                    <VisualState.Setters>
                        <Setter Property="BackgroundColor"
                                Value="White" />
                    </VisualState.Setters>
                </VisualState>
            </VisualStateGroup>
        </VisualStateGroupList>
    </Setter>
</Style>
...
<Grid>
    <Frame BackgroundColor="White"
           CornerRadius="12"
           Margin="24"
           HorizontalOptions="Center"
           VerticalOptions="Center">
        <StackLayout Orientation="Horizontal">
            <CheckBox x:Name="checkBox"
                      VerticalOptions="Center" />
            <Label Text="Check the CheckBox to modify the Grid background color."
                   VerticalOptions="Center" />
        </StackLayout>
    </Frame>
</Grid>

在此示例中,隐式 StyleGrid 对象为目标。 当 CheckBoxIsChecked 属性为 false 时,Grid 的背景色设置为白色。 当 CheckBox.IsChecked 属性变为 true 时,将触发 VisualState 更改,并且 Grid 的背景色变为黑色。

设备状态触发器

DeviceStateTrigger 根据应用运行所在的设备平台触发 VisualState 更改。 此触发器有以下一个可绑定属性:

注意

由于 DeviceStateTrigger 派生自 StateTriggerBase 类,因此可以将事件处理程序附加到 IsActiveChanged 事件。

下面的 XAML 示例展示了包含 DeviceStateTrigger 对象的 Style

<Style x:Key="DeviceStateTriggerPageStyle"
       TargetType="ContentPage">
    <Setter Property="VisualStateManager.VisualStateGroups">
        <VisualStateGroupList>
            <VisualStateGroup>
                <VisualState x:Name="iOS">
                    <VisualState.StateTriggers>
                        <DeviceStateTrigger Device="iOS" />
                    </VisualState.StateTriggers>
                    <VisualState.Setters>
                        <Setter Property="BackgroundColor"
                                Value="Silver" />
                    </VisualState.Setters>
                </VisualState>
                <VisualState x:Name="Android">
                    <VisualState.StateTriggers>
                        <DeviceStateTrigger Device="Android" />
                    </VisualState.StateTriggers>
                    <VisualState.Setters>
                        <Setter Property="BackgroundColor"
                                Value="#2196F3" />
                    </VisualState.Setters>
                </VisualState>
            </VisualStateGroup>
        </VisualStateGroupList>
    </Setter>
</Style>

在此示例中,显式 StyleContentPage 对象为目标。 使用该样式的 ContentPage 对象在 iOS 上将其背景色设置为银色,在 Android 上将其背景色设置为淡蓝色。

方向状态触发器

当设备的方向更改时,OrientationStateTrigger 触发 VisualState 更改。 此触发器有以下一个可绑定属性:

注意

由于 OrientationStateTrigger 派生自 StateTriggerBase 类,因此可以将事件处理程序附加到 IsActiveChanged 事件。

下面的 XAML 示例展示了包含 OrientationStateTrigger 对象的 Style

<Style x:Key="OrientationStateTriggerPageStyle"
       TargetType="ContentPage">
    <Setter Property="VisualStateManager.VisualStateGroups">
        <VisualStateGroupList>
            <VisualStateGroup>
                <VisualState x:Name="Portrait">
                    <VisualState.StateTriggers>
                        <OrientationStateTrigger Orientation="Portrait" />
                    </VisualState.StateTriggers>
                    <VisualState.Setters>
                        <Setter Property="BackgroundColor"
                                Value="Silver" />
                    </VisualState.Setters>
                </VisualState>
                <VisualState x:Name="Landscape">
                    <VisualState.StateTriggers>
                        <OrientationStateTrigger Orientation="Landscape" />
                    </VisualState.StateTriggers>
                    <VisualState.Setters>
                        <Setter Property="BackgroundColor"
                                Value="White" />
                    </VisualState.Setters>
                </VisualState>
            </VisualStateGroup>
        </VisualStateGroupList>
    </Setter>
</Style>

在此示例中,显式 StyleContentPage 对象为目标。 ContentPage 对象使用的 style 在方向为垂直时将背景色设置为银色,在方向为水平时将背景色设置为白色。