Xamarin.Forms 提供了底下四種觸發方法可以使用
屬性觸發 Property Trigger - 當所指定的屬性值有變更並且符合指定的條件,就會進行相關內容設定。
資料觸發 Data Trigger - 若這個屬性使用了資料繫結來綁定其屬性值,可以使用這個方式,當綁定的屬性值符合觸發條件,就可以進行相關內容設定。
事件觸發 Event Trigger - 當所指定的事件發生的時候,就會被觸發。
多重觸發 Multi Trigger - Xamarin.Forms 允許多重觸發條件的設定。
要定義觸發非常的容易,因為每個 View 都會擁有一個 Triggers 屬性,使用 Property-Element 的標示方式,就可以定義這個 View 的觸發條件與相關動作。
範例專案
在這個範例中,完全沒有用到 ViewModel 與 Code Behind,就可以做到
屬性觸發 Property Trigger
在其 Triggers 屬性內,可以定義屬性觸發,例如這樣:
<Trigger TargetType="Entry" Property="IsFocused" Value="True" >
這裡定義了,這個 Entry 控制項,當其 IsFocused
屬性值為 True 的時候,會進行底下的 Setter 的設定;講白話一點,就是當使用者點選到這個控制項之後,這個 Entry 控制項的三個屬性就會跟著變更;若使用者切換到其他的控制項內,則這三個屬性值,就會回到原先的設定值。 <Entry Placeholder="請輸入名稱" FontSize="14">
<Entry.Triggers>
<Trigger TargetType="Entry" Property="IsFocused" Value="True" >
<Setter Property="BackgroundColor" Value="Black" />
<Setter Property="PlaceholderColor" Value="Yellow" />
<Setter Property="TextColor" Value="White" />
</Trigger>
</Entry.Triggers>
</Entry>
資料觸發 Data Trigger
在這個範例中,需要做到當 Entry 有輸入資料的時候,該 Entry 底下的按鈕才會啟用,也就是使用者可以來點選。
要做到這樣的效果,需要在 Button 控制項內 Triggers 設定一個觸發條件,就是
DataTrigger
,但是,在這裡並不使用 Value 這個屬性,而是使用了 Binding
這個屬性,裡面指定了綁定的來源;在這個範例中,透過了 Source 指定綁定來源為另外一個 Entry 控制項內的 Text.Length 這個使用。當這個屬性值為 0 的時候,就會觸發條件,設定這個按鈕為停止啟用狀態。這也就是說,當使用者在 Entry 內輸入資料的時候,這個按鈕的 IsEnabled 就會變成 True,也就是,這個按鈕可以讓使用者點選了。 <!-- 提示: 確定 Text="" 需要有預設值,否則,會以問題 -->
<Entry x:Name="entry" Text="" Placeholder="這個欄位需要輸入"
FontSize="14" TextColor="Blue" />
<Button Text="儲存" HorizontalOptions="Center">
<Button.Triggers>
<DataTrigger TargetType="Button"
Binding="{Binding Source={x:Reference entry},
Path=Text.Length}" Value="0">
<Setter Property="IsEnabled" Value="False" />
</DataTrigger>
</Button.Triggers>
</Button>
事件觸發 Event Trigger
事件觸發則是更加簡單了,透過設定
<EventTrigger Event="TextChanged">
設定 Event 這個屬性,當其指定的事件發生之後,就會執行 <local:NumericValidationTriggerAction />
內的 Invoke 方法。 <Entry Placeholder="請輸入名稱" FontSize="14">
<Entry.Triggers>
<EventTrigger Event="TextChanged">
<local:NumericValidationTriggerAction />
</EventTrigger>
</Entry.Triggers>
</Entry>
NumericValidationTriggerAction 類別需要繼承
TriggerAction<T>
,並且定義 Invoke 這個方法 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;
entry.Scale = 1.4;
}
}
多重觸發 Multi Trigger
多重觸發看起來與屬性觸發和資料觸發類似,但是,在多重觸發中,可以設定更多的觸發條件,必須當所有設定的條件都符合的時候,才會進行觸發的 Setter 設定動作。
在底下的範例中,按鈕使用了
<MultiTrigger TargetType="Button">
,也就是使用了多重觸發。
這裡定義了兩個觸發條件,也就是當上面兩個 Entry 都沒有輸入任何內容的時候,這個多重觸發條件就會啟動,這個時候,這個按鈕就會被設定 IsEnabled的值為 False,就是這個按鈕是無法使用的。
講白話一點,當這兩個 Entry 任何一個或者兩個,都有輸入內容的時候,這個按鈕 IsEnabled 就會為 True,就是可以被點選。
<!--這裡為什麼無法做到兩個同時都要輸入,才能夠觸發呢?-->
<Label Text="多重觸發 Multi Trigger(任一有輸入)" TextColor="Blue"/>
<Entry x:Name="user" Text="" Placeholder="請輸入使用者名稱" FontSize="14" />
<Entry x:Name="pwd" Text="" Placeholder="請輸入密碼" IsPassword="True" FontSize="14" />
<Button x:Name="loginButton" Text="Login"
HorizontalOptions="Center" >
<Button.Triggers>
<MultiTrigger TargetType="Button">
<MultiTrigger.Conditions>
<BindingCondition Binding="{Binding Source={x:Reference user},
Path=Text.Length}" Value="0" />
<BindingCondition Binding="{Binding Source={x:Reference pwd},
Path=Text.Length}" Value="0" />
</MultiTrigger.Conditions>
<Setter Property="IsEnabled" Value="False" />
</MultiTrigger>
</Button.Triggers>
</Button>
在上面的多重觸發應用中,若我們想要做到這兩個 Entry 都有輸入值的時候,按鈕才可以使用,那麼,這樣如何做到呢?這個時候,就要看底下的範例。
在這裡,還是一樣要設定
Button.Triggers
的 MultiTrigger
條件,不過,在這裡,按鈕預設是被停用狀態。
在進行設定
BindingCondition
條件的時候,透過了數值轉換器來將字串的長度,轉換成為布林值。
所有,兩個多重觸發的條件,都是當使用者有輸入內容的時候( Text.Length > 0) ,其條件就會成立。
請記得多重觸發是
必須當所有設定的條件都符合的時候,才會進行觸發的 Setter 設定動作
這樣的規則,因此,在此就可以做到,兩個 Entry 都有輸入內容的時候,按鈕才會啟用。 <!--這裡需要兩個文字輸入盒同時都要有輸入,按鈕才會啟用-->
<Label Text="多重觸發 Multi Trigger(都要有輸入)" TextColor="Blue"/>
<Entry x:Name="user1" Text="" Placeholder="請輸入使用者名稱" FontSize="14" />
<Entry x:Name="pwd1" Text="" Placeholder="請輸入密碼" IsPassword="True" FontSize="14" />
<Button x:Name="login1Button" Text="Login"
FontSize="Large"
HorizontalOptions="Center"
IsEnabled="false">
<Button.Triggers>
<MultiTrigger TargetType="Button">
<MultiTrigger.Conditions>
<BindingCondition Binding="{Binding Source={x:Reference user1},
Path=Text.Length,
Converter={StaticResource dataHasBeenEntered}}"
Value="true" />
<BindingCondition Binding="{Binding Source={x:Reference pwd1},
Path=Text.Length,
Converter={StaticResource dataHasBeenEntered}}"
Value="true" />
</MultiTrigger.Conditions>
<Setter Property="IsEnabled" Value="True" />
</MultiTrigger>
</Button.Triggers>
</Button>
這個 MultiTriggerConverter 數值轉換器,會收到一個整數數值,若該數值大於 0,則會回傳 True,否則,會回傳 False。這表示了,當使用者在 Entry 有輸入內容的時候,會經過數值轉換器得到 True 的值。
class MultiTriggerConverter : IValueConverter
{
public object Convert(object value, Type targetType,
object parameter, CultureInfo culture)
{
if ((int)value > 0)
return true; // data has been entered
else
return false; // input is empty
}
public object ConvertBack(object value, Type targetType,
object parameter, CultureInfo culture)
{
throw new NotSupportedException();
}
}
完整的 XAML
<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:prism="clr-namespace:Prism.Mvvm;assembly=Prism.Forms"
xmlns:local="clr-namespace:XFTrigger"
prism:ViewModelLocator.AutowireViewModel="True"
x:Class="XFTrigger.Views.MainPage"
Title="MainPage">
<ContentPage.Resources>
<ResourceDictionary>
<local:MultiTriggerConverter x:Key="dataHasBeenEntered" />
</ResourceDictionary>
</ContentPage.Resources>
<StackLayout HorizontalOptions="Center" VerticalOptions="Center">
<Label Text="屬性觸發 Property Trigger" TextColor="Blue"/>
<Entry Placeholder="請輸入名稱" FontSize="14">
<Entry.Triggers>
<Trigger TargetType="Entry" Property="IsFocused" Value="True" >
<Setter Property="BackgroundColor" Value="Black" />
<Setter Property="PlaceholderColor" Value="Yellow" />
<Setter Property="TextColor" Value="White" />
</Trigger>
</Entry.Triggers>
</Entry>
<Label Text="資料觸發 Data Trigger"/>
<!-- 提示: 確定 Text="" 需要有預設值,否則,會以問題 -->
<Entry x:Name="entry" Text="" Placeholder="這個欄位需要輸入"
FontSize="14" TextColor="Blue" />
<Button Text="儲存" HorizontalOptions="Center">
<Button.Triggers>
<DataTrigger TargetType="Button"
Binding="{Binding Source={x:Reference entry},
Path=Text.Length}" Value="0">
<Setter Property="IsEnabled" Value="False" />
</DataTrigger>
</Button.Triggers>
</Button>
<Label Text="事件觸發 Event Trigger" TextColor="Blue"/>
<Entry Placeholder="請輸入名稱" FontSize="14">
<Entry.Triggers>
<EventTrigger Event="TextChanged">
<local:NumericValidationTriggerAction />
</EventTrigger>
</Entry.Triggers>
</Entry>
<!--這裡為什麼無法做到兩個同時都要輸入,才能夠觸發呢?-->
<Label Text="多重觸發 Multi Trigger(任一有輸入)" TextColor="Blue"/>
<Entry x:Name="user" Text="" Placeholder="請輸入使用者名稱" FontSize="14" />
<Entry x:Name="pwd" Text="" Placeholder="請輸入密碼" IsPassword="True" FontSize="14" />
<Button x:Name="loginButton" Text="Login"
HorizontalOptions="Center" >
<Button.Triggers>
<MultiTrigger TargetType="Button">
<MultiTrigger.Conditions>
<BindingCondition Binding="{Binding Source={x:Reference user},
Path=Text.Length}" Value="0" />
<BindingCondition Binding="{Binding Source={x:Reference pwd},
Path=Text.Length}" Value="0" />
</MultiTrigger.Conditions>
<Setter Property="IsEnabled" Value="False" />
</MultiTrigger>
</Button.Triggers>
</Button>
<!--這裡需要兩個文字輸入盒同時都要有輸入,按鈕才會啟用-->
<Label Text="多重觸發 Multi Trigger(都要有輸入)" TextColor="Blue"/>
<Entry x:Name="user1" Text="" Placeholder="請輸入使用者名稱" FontSize="14" />
<Entry x:Name="pwd1" Text="" Placeholder="請輸入密碼" IsPassword="True" FontSize="14" />
<Button x:Name="login1Button" Text="Login"
FontSize="Large"
HorizontalOptions="Center"
IsEnabled="false">
<Button.Triggers>
<MultiTrigger TargetType="Button">
<MultiTrigger.Conditions>
<BindingCondition Binding="{Binding Source={x:Reference user1},
Path=Text.Length,
Converter={StaticResource dataHasBeenEntered}}"
Value="true" />
<BindingCondition Binding="{Binding Source={x:Reference pwd1},
Path=Text.Length,
Converter={StaticResource dataHasBeenEntered}}"
Value="true" />
</MultiTrigger.Conditions>
<Setter Property="IsEnabled" Value="True" />
</MultiTrigger>
</Button.Triggers>
</Button>
</StackLayout>
</ContentPage>