触发器
在最普遍(和最模糊)的意义上,触发器是导致响应的条件。 更具体地说,触发器通过设置另一个属性或运行一些代码来响应属性更改或触发事件。 几乎总是,设置的属性或运行的代码涉及用户界面,并在XAML中表示。
VisualElement和Style都定义了IList 类型的Triggers属性。 抽象TriggerBase类派生自BindableObject。 四个密封类派生自TriggerBase:
- Trigger设置属性(或运行代码)以响应属性更改。
- EventTrigger,用于运行代码以响应事件。
- DataTrigger,用于设置属性(或运行代码)以响应数据绑定中引用的属性更改。
- MultiTrigger用于在发生多个触发器时设置属性(或运行代码)。
这些之间的差异将在实践中变得更加清晰。
最简单的触发器
在其通常的形式中,Trigger类检查元素的属性更改,并通过设置同一元素的另一个属性来响应。
例如,假设您设计了一个包含多个Entry视图的页面。 您已经确定当特定条目获得输入焦点时,您希望条目变大。 您希望使条目脱颖而出,包括用户键入的文本。
更具体地说,当Entry的IsFocused属性变为True时,您希望Entry的Scale属性设置为1.5。 当IsFocused属性恢复为False时,您希望Scale属性也恢复为其先前的值。
为了适应这个概念,Trigger定义了三个属性:
- BindableProperty类型的属性。
- 对象类型的值。
- IList类型的setter。 这是Trigger的内容属性。
必须设置所有这些属性才能使触发器起作用。 从TriggerBase,Trigger继承了另一个基本属性:
- TargetType 类型为Type。
这是连接触发器的元素的类型。
Trigger的Property和Value属性有时被认为是一个条件。 当Property引用的属性的值等于Value时,条件为true,并且Setter对象的集合将应用于该元素。
正如您将在第12章“样式”中回忆的那样,Setter定义了两个与前两个Trigger属性相同的属性:
- Property 类型为BindableProperty。
- Value类型为Object。
使用触发器,我们只处理可绑定属性。 Trigger条件属性必须由BindableProperty以及Setter设置的属性支持。
当条件变为false时,Setter对象是“未应用的”,这意味着Setter引用的属性将恢复为没有Setter的值,这可能是属性的默认值,直接设置的值 元素,或通过Style应用的值。
这是EntryPop程序的XAML文件。 页面上的三个Entry视图中的每一个都使用Entry.Triggers属性元素标记将一个Trigger对象添加到其Triggers集合中。 每个Trigger对象都有一个Setter添加到其Setters集合中。 因为Setters是Trigger的content属性,所以不需要Trigger.Setters属性元素标记:
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="EntryPop.EntryPopPage"
Padding="20, 50, 120, 0">
<StackLayout Spacing="20">
<Entry Placeholder="enter name"
AnchorX="0">
<Entry.Triggers>
<Trigger TargetType="Entry" Property="IsFocused" Value="True">
<Setter Property="Scale" Value="1.5" />
</Trigger>
</Entry.Triggers>
</Entry>
<Entry Placeholder="enter address"
AnchorX="0">
<Entry.Triggers>
<Trigger TargetType="Entry" Property="IsFocused" Value="True">
<Setter Property="Scale" Value="1.5" />
</Trigger>
</Entry.Triggers>
</Entry>
<Entry Placeholder="enter city and state"
AnchorX="0">
<Entry.Triggers>
<Trigger TargetType="Entry" Property="IsFocused" Value="True">
<Setter Property="Scale" Value="1.5" />
</Trigger>
</Entry.Triggers>
</Entry>
</StackLayout>
</ContentPage>
每个Trigger对象必须设置其TargetType,在这种情况下,这是一个Entry。 在内部,Trigger使用PropertyChanged处理程序来监视IsFocused属性的值。 当该属性等于True时,单个Setter对象将Scale属性设置为1.5。 AnchorX设置为零会指示从Entry的左侧进行缩放。 (AnchorX的非默认值表示如果更改iOS屏幕的方向,则无法正确定位Entry视图。)
当Entry失去输入焦点并且IsFocused属性再次变为False时,Trigger会自动删除Setter的应用程序,在这种情况下,Scale属性将恢复为
它的预触发值,不一定是它的默认值。
以下是带有输入焦点的放大的Entry视图:
此示例中的每个Entry视图只有一个Trigger,每个Trigger只有一个Setter,但在一般情况下,visual元素在其Triggers集合中可以有多个Trigger对象,每个Trigger在其Setters集合中可以有多个Setter对象。
如果要在代码中执行类似的操作,则可以将PropertyChanged事件处理程序附加到每个Entry,并通过设置Scale属性来响应IsFocused属性中的更改。 触发器的优点是你可以在定义元素的位置完成标记的整个工作,留下工作代码可能比增加Entry元素的大小更重要!
因此,您不太可能需要在代码中创建Trigger对象。 从来没有,EntryPopCode程序演示了你是如何做到的。 代码已被设计为尽可能类似于XAML:
public class EntryPopCodePage : ContentPage
{
public EntryPopCodePage()
{
Padding = new Thickness(20, 50, 120, 0);
Content = new StackLayout
{
Spacing = 20,
Children =
{
new Entry
{
Placeholder = "enter name",
AnchorX = 0,
Triggers =
{
new Trigger(typeof(Entry))
{
Property = Entry.IsFocusedProperty,
Value = true,
Setters =
{
new Setter
{
Property = Entry.ScaleProperty,
Value = 1.5
}
}
}
}
},
new Entry
{
Placeholder = "enter addresss",
AnchorX = 0,
Triggers =
{
new Trigger(typeof(Entry))
{
Property = Entry.IsFocusedProperty,
Value = true,
Setters =
{
new Setter
{
Property = Entry.ScaleProperty,
Value = 1.5
}
}
}
}
},
new Entry
{
Placeholder = "enter city and state",
AnchorX = 0,
Triggers =
{
new Trigger(typeof(Entry))
{
Property = Entry.IsFocusedProperty,
Value = true,
Setters =
{
new Setter
{
Property = Entry.ScaleProperty,
Value = 1.5
}
}
}
}
}
}
};
}
}
XAML和代码之间唯一真正的区别是TargetType属性的处理。 在XAML中,TargetType属性在三个Trigger定义中的每一个中设置为“Entry”。 但是,在代码中,必须将typeof(Entry)作为参数传递给Trigger构造函数。 如果查看Trigger类的文档,则会发现TargetType属性是get-only。 XAML解析器使用TargetType属性设置来实例化Trigger对象。
Style类还定义了IList 类型的Triggers属性,这意味着您可以使用Style在多个元素之间共享Trigger对象。 StyledTriggers程序显示了如何。 请注意,Style和Trigger标记都包含TargetType属性设置。 Style包含一个Setter对象,并为单个Trigger对象使用Style.Triggers属性 - 元素标记,该对象还包含Setter对象:
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="StyledTriggers.StyledTriggersPage"
Padding="20, 50, 120, 0">
<ContentPage.Resources>
<ResourceDictionary>
<Style TargetType="Entry">
<Setter Property="AnchorX" Value="0" />
<Style.Triggers>
<Trigger TargetType="Entry" Property="IsFocused" Value="True">
<Setter Property="Scale" Value="1.5" />
</Trigger>
</Style.Triggers>
</Style>
</ResourceDictionary>
</ContentPage.Resources>
<StackLayout Spacing="20">
<Entry Placeholder="enter name" />
<Entry Placeholder="enter address" />
<Entry Placeholder="enter city and state" />
</StackLayout>
</ContentPage>
由于Style没有字典键,因此它是一种隐式样式,可自动应用于Entry类型的所有元素。 单个Entry元素只需包含每个元素的唯一元素。
也许在尝试使用EntryPop程序(或两个变体)之后,您决定不希望Scale属性简单地“弹出”到值1.5。 你想要一个动画。 您希望它在获得输入焦点时“膨胀”大小,并在失去输入焦点时将其动画恢复正常。
那也是可能的。