Xamarin.Forms 觸發程序
觸發程序可讓您用 XAML 以宣告方式表達動作,根據事件或屬性變更改變控制項的外觀。 此外,狀態觸發程序是一組特殊化觸發程序,其定義何時應套用 VisualState
。
您可以將觸發程序直接指派給控制項,或將它新增至頁面層級或應用程式層級的資源字典,以套用至多個控制項。
屬性觸發程序
簡單的觸發程序完全以 XAML 表達,新增 Trigger
項目至控制項的觸發程序集合。
此範例示範在 Entry
收到焦點時,變更其背景色彩的觸發程序:
<Entry Placeholder="enter name">
<Entry.Triggers>
<Trigger TargetType="Entry"
Property="IsFocused" Value="True">
<Setter Property="BackgroundColor" Value="Yellow" />
<!-- multiple Setters elements are allowed -->
</Trigger>
</Entry.Triggers>
</Entry>
觸發程序宣告的重要部分包括:
TargetType - 觸發程序適用的控制項類型。
Property - 控制項上受監視的屬性。
Value - 針對受監視的屬性發生時,導致啟動觸發程序的值。
Setter - 符合觸發程序條件時可以新增
Setter
項目的集合。 您必須指定要設定的Property
和Value
。EnterActions 和 ExitActions (未顯示) - 以程式碼撰寫,且可以和
Setter
項目一起使用,或是用來代替它。 其描述如下。
使用樣式套用觸發程序
觸發程序也可以新增至控制項的 Style
宣告、頁面上或應用程式 ResourceDictionary
。 此範例宣告隱含的樣式 (亦即,未設定 Key
),這表示其將適用於頁面上的所有 Entry
控制項。
<ContentPage.Resources>
<ResourceDictionary>
<Style TargetType="Entry">
<Style.Triggers>
<Trigger TargetType="Entry"
Property="IsFocused" Value="True">
<Setter Property="BackgroundColor" Value="Yellow" />
<!-- multiple Setters elements are allowed -->
</Trigger>
</Style.Triggers>
</Style>
</ResourceDictionary>
</ContentPage.Resources>
資料觸發程序
資料觸發程序使用資料繫結來監視另一個控制項,導致呼叫 Setter
。 請設定 Binding
屬性來監視指定的值,而不是屬性觸發程序中的 Property
屬性。
下列範例使用資料繫結語法 {Binding Source={x:Reference entry}, Path=Text.Length}
這就是我們參考另一個控件屬性的方式。 當 entry
的長度為零時,會啟動觸發程序。 在此範例中,觸發程序會在輸入為空時停用按鈕。
<!-- the x:Name is referenced below in DataTrigger-->
<!-- tip: make sure to set the Text="" (or some other default) -->
<Entry x:Name="entry"
Text=""
Placeholder="required field" />
<Button x:Name="button" Text="Save"
FontSize="Large"
HorizontalOptions="Center">
<Button.Triggers>
<DataTrigger TargetType="Button"
Binding="{Binding Source={x:Reference entry},
Path=Text.Length}"
Value="0">
<Setter Property="IsEnabled" Value="False" />
<!-- multiple Setters elements are allowed -->
</DataTrigger>
</Button.Triggers>
</Button>
提示
評估 Path=Text.Length
時一律會提供目標屬性的預設值 (例如 Text=""
),否則會是 null
,而且觸發程式無法如您所預期般運作。
除了指定 Setter
之外,您也可以提供 EnterActions
和 ExitActions
。
事件觸發程序
EventTrigger
項目只需要 Event
屬性,例如下列範例中的 "Clicked"
。
<EventTrigger Event="Clicked">
<local:NumericValidationTriggerAction />
</EventTrigger>
請注意,沒有 Setter
項目,但是有 local:NumericValidationTriggerAction
所定義類別的參考,它需要在頁面的 XAML 中宣告 xmlns:local
:
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:local="clr-namespace:WorkingWithTriggers;assembly=WorkingWithTriggers"
類別本身會實作 TriggerAction
,這表示每次觸發程序事件發生時,它應該提供所呼叫 Invoke
方法的覆寫。
觸發程序動作實作應該:
實作泛型
TriggerAction<T>
類別,且泛型參數對應觸發程序將套用至的控制項類型。 您可以使用 Superclass,例如VisualElement
,來撰寫使用各種控制項的觸發程序動作,或指定如Entry
控制項類型。覆寫
Invoke
方法 - 每當符合觸發程序準則時便會呼叫它。選擇性地公開可在宣告觸發程序時,於 XAML 中設定的屬性。 如需相關範例,請參閱隨附範例應用程式中的
VisualElementPopTriggerAction
類別。
public class NumericValidationTriggerAction : TriggerAction<Entry>
{
protected override void Invoke (Entry entry)
{
double result;
bool isValid = Double.TryParse (entry.Text, out result);
entry.TextColor = isValid ? Color.Default : Color.Red;
}
}
您可以從 XAML 取用事件觸發程序:
<EventTrigger Event="TextChanged">
<local:NumericValidationTriggerAction />
</EventTrigger>
在 ResourceDictionary
中共用觸發程序時請小心,將會在控制項之間共用一個執行個體,因此設定一次的任何狀態將會適用於全部。
請注意,事件觸發程序不支援 EnterActions
和 ExitActions
,如下所述。
多重觸發程序
MultiTrigger
看起來類似於 Trigger
或 DataTrigger
,但它可以有多個條件。 所有條件必須都為 true 才會觸發 Setter
。
以下是繫結至兩個不同輸入 (email
和 phone
) 的按鈕觸發程序範例:
<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>
Conditions
集合可能也會包含 PropertyCondition
項目,如下所示:
<PropertyCondition Property="Text" Value="OK" />
建置「需要全部」的多重觸發程序
多重觸發程序只有在所有條件都成立時,只會更新其控制項。 測試「所有欄位長度都是零」(例如必須完成所有輸入的登入頁面),是棘手的,因為您想要條件“其中 Text.Length > 0”,但無法在 XAML 中表示。
這可以使用 IValueConverter
完成。 以下的轉換器程式碼會將 Text.Length
繫結轉換成 bool
,指出欄位是否為空白:
public class MultiTriggerConverter : IValueConverter
{
public object Convert(object value, Type targetType,
object parameter, CultureInfo culture)
{
if ((int)value > 0) // length > 0 ?
return true; // some data has been entered
else
return false; // input is empty
}
public object ConvertBack(object value, Type targetType,
object parameter, CultureInfo culture)
{
throw new NotSupportedException ();
}
}
若要在多重觸發程序中使用這個轉換器,先將其新增至頁面的資源字典 (附上自訂的 xmlns:local
命名空間定義):
<ResourceDictionary>
<local:MultiTriggerConverter x:Key="dataHasBeenEntered" />
</ResourceDictionary>
XAML 如下所示。 請注意第一個多重觸發程序範例的下列差異:
- 按鈕預設已設定
IsEnabled="false"
。 - 多重觸發程序條件使用轉換器,將
Text.Length
值變為boolean
。 - 所有條件都為
true
時,setter 會讓按鈕的IsEnabled
屬性成為true
。
<Entry x:Name="user" Text="" Placeholder="user name" />
<Entry x:Name="pwd" Text="" Placeholder="password" />
<Button x:Name="loginButton" Text="Login"
FontSize="Large"
HorizontalOptions="Center"
IsEnabled="false">
<Button.Triggers>
<MultiTrigger TargetType="Button">
<MultiTrigger.Conditions>
<BindingCondition Binding="{Binding Source={x:Reference user},
Path=Text.Length,
Converter={StaticResource dataHasBeenEntered}}"
Value="true" />
<BindingCondition Binding="{Binding Source={x:Reference pwd},
Path=Text.Length,
Converter={StaticResource dataHasBeenEntered}}"
Value="true" />
</MultiTrigger.Conditions>
<Setter Property="IsEnabled" Value="True" />
</MultiTrigger>
</Button.Triggers>
</Button>
這些螢幕擷取畫面顯示上述兩個多重觸發程序範例之間的差異。 在畫面頂端的文字輸入,只需要有一個 Entry
即可啟用 [儲存] 按鈕。
在畫面底部,[登入] 按鈕保持非使用中,直到兩個欄位都包含資料為止。
EnterActions 和 ExitActions
另一種在觸發程序發生時實作變更的方法,是藉由新增 EnterActions
和 ExitActions
集合,並指定 TriggerAction<T>
實作。
EnterActions
集合可用來定義符合觸發條件時所叫用 TriggerAction
物件的 IList
。 ExitActions
集合可用來定義觸發條件不再符合之後所叫用 TriggerAction
物件的 IList
。
注意
EventTrigger
類別會忽略 EnterActions
和 ExitActions
集合中定義的 TriggerAction
物件。
您可以「同時」在觸發程序中提供 EnterActions
和 ExitActions
,以及 Setter
;但請注意,會立即呼叫 Setter
(其不會等待 EnterAction
或 ExitAction
完成)。 或者,您可以在程式碼中執行一切,完全不使用 Setter
。
<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>
<!-- You can use both Enter/Exit and Setter together if required -->
</Trigger>
</Entry.Triggers>
</Entry>
如往常,在 XAML 中參考類別時,應該宣告命名空間,例如此處所示的 xmlns:local
:
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:local="clr-namespace:WorkingWithTriggers;assembly=WorkingWithTriggers"
FadeTriggerAction
程式碼如下所示:
public class FadeTriggerAction : TriggerAction<VisualElement>
{
public int StartsFrom { set; get; }
protected override void Invoke(VisualElement sender)
{
sender.Animate("FadeTriggerAction", new Animation((d) =>
{
var val = StartsFrom == 1 ? d : 1 - d;
// so i was aiming for a different color, but then i liked the pink :)
sender.BackgroundColor = Color.FromRgb(1, val, 1);
}),
length: 1000, // milliseconds
easing: Easing.Linear);
}
}
狀態觸發程序
狀態觸發程式是一組特殊的觸發程式,可定義應套用 的條件 VisualState
。
狀態觸發程序會新增至 VisualState
的 StateTriggers
集合。 此集合可以包含單一狀態觸發程序或多個狀態觸發程序。 當集合中的任何狀態觸發程序為作用中時,將會套用 VisualState
。
使用狀態觸發程式來控制視覺狀態時, Xamarin.Forms 會使用下列優先順序規則來判斷哪一個觸發程式 (以及對應的 VisualState
) 為作用中:
- 衍生自
StateTriggerBase
的任何觸發程序。 - 因為符合
MinWindowWidth
條件,所以已啟用AdaptiveTrigger
。 - 因為符合
MinWindowHeight
條件,所以已啟用AdaptiveTrigger
。
如果多個觸發程序同時處於作用中狀態 (例如,兩個自訂觸發程序),則會優先使用標記中宣告的第一個觸發程序。
注意
狀態觸發程序可以在 Style
中設定,或直接在元素上設定。
如需視覺狀態的詳細資訊,請參閱 Xamarin.Forms Visual State Manager。
狀態觸發程序
衍生自 StateTriggerBase
類別的 StateTrigger
類別具有 IsActive
可繫結屬性。 當 IsActive
屬性變更值時,StateTrigger
會觸發 VisualState
變更。
StateTriggerBase
類別 (所有狀態觸發程序的基底類別) 具有 IsActive
屬性與 IsActiveChanged
事件。 每當發生 VisualState
變更時,就會引發此事件。 此外,類別 StateTriggerBase
具有可 OnAttached
覆寫的 和 OnDetached
方法。
重要
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>
在此範例中,隱含的 Style
以 Grid
物件為目標。 當繫結物件的 IsToggled
屬性為 true
時,Grid
的背景色彩會設定為黑色。 當繫結物件的 IsToggled
屬性變成 false
時,就會觸發 VisualState
變更,而且 Grid
的背景色彩會變成白色。
此外,每次發生 VisualState
變更時,就會引發 VisualState
的 IsActiveChanged
事件。 每個 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
類別來建立,並覆寫 OnAttached
和 OnDetached
方法來執行任何必要的註冊和清除。
調適型觸發程序
當視窗具有指定的高度或寬度時,AdaptiveTrigger
會觸發 VisualState
變更。 此觸發程序有兩個可繫結的屬性:
MinWindowHeight
(double
型別),指出應套用VisualState
的最小視窗高度。MinWindowWidth
(double
型別),指出應套用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>
在此範例中,隱含的 Style
以 StackLayout
物件為目標。 當視窗寬度介於 0 到 800 裝置獨立單位之間時,套用 Style
的 StackLayout
物件將會有垂直方向。 當視窗寬度 >= 800 個裝置獨立單位時, VisualState
就會觸發變更,而 StackLayout
方向會變更為水準:
MinWindowHeight
與 MinWindowWidth
屬性可以單獨使用,也可以相互結合使用。 下列 XAML 顯示設定這兩個屬性的範例:
<AdaptiveTrigger MinWindowWidth="800"
MinWindowHeight="1200"/>
在這裡範例中,AdaptiveTrigger
表示當目前的視窗寬度為 >= 800 個裝置獨立單位,而目前的視窗高度>為 = 1200 個裝置獨立單位時,就會套用對應的 VisualState
。
比較狀態觸發程序
CompareStateTrigger
會在屬性等於特定值時,觸發 VisualState
變更。 此觸發程序有兩個可繫結的屬性:
Property
(object
型別),指出將由觸發程序比較的屬性。Value
(object
型別),指出應套用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>
在此範例中,隱含的 Style
以 Grid
物件為目標。 當 CheckBox
的 IsChecked
屬性為 false
時,Grid
的背景色彩會設定為白色。 當 CheckBox.IsChecked
屬性變成 true
時,就會觸發 VisualState
變更,而 Grid
的背景色彩會變為黑色:
裝置狀態觸發程序
DeviceStateTrigger
會根據應用程式執行所在的裝置平台,觸發 VisualState
變更。 此觸發程序具有單一可繫結屬性:
Device
(string
型別),指出應在其上套用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>
<VisualState x:Name="UWP">
<VisualState.StateTriggers>
<DeviceStateTrigger Device="UWP" />
</VisualState.StateTriggers>
<VisualState.Setters>
<Setter Property="BackgroundColor"
Value="Aquamarine" />
</VisualState.Setters>
</VisualState>
</VisualStateGroup>
</VisualStateGroupList>
</Setter>
</Style>
在此範例中,明確的 Style
以 ContentPage
物件為目標。 取用樣式的 ContentPage
物件,在 iOS 上會將其背景色彩設定為銀色、在 Android 上設定為淺藍色,而在 UWP 上設定為青綠色。 下列螢幕擷取畫面顯示在 iOS 與 Android 上產生的頁面:
方向狀態觸發程序
當裝置的方向變更時,OrientationStateTrigger
會觸發 VisualState
變更。 此觸發程序具有單一可繫結屬性:
Orientation
(DeviceOrientation
型別),指出應套用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>
在此範例中,明確的 Style
以 ContentPage
物件為目標。 取用樣式的 ContentPage
物件,會在方向為直向時將其背景色彩設定為銀色,並在方向為橫向時將其背景色彩設定為白色。