學習目標
- Behavior- 元件的自定義附加行為
- 在 Behavior 內加入 Bindable Property
Trigger 和 Behavior 其實滿像的,所有 Trigger 可以做的事情都能用 Behavior 完成,
但,Behavior 要寫的程式碼比 Trigger 多,
所以,能用 Trigger 解決的問題就不要用 Behavior !!!
Behavior 就像是 Trigger 的加強版,當然也可以在 XAML 重複使用。
等等,所以 Behavior 到底是什麼??
可以想成:
幫 Visual Element 手動附加新功能。
來看一下範例,
當 Entry 輸入非數字時,文字會變成紅色,
本範例就是附加 判斷是否為數字 的新功能
先來看 Trigger 寫法
.cs
namespace Xamarin.FormsBook.Toolkit { public class NumericValidationAction : TriggerActionXAML{ protected override void Invoke(Entry entry) { double result; bool isValid = Double.TryParse(entry.Text, out result); entry.TextColor = isValid ? Color.Default : Color.Red; } } }
<Entry Placeholder="Enter a System.Double"> <Entry.Triggers> <EventTrigger Event="TextChanged"> <toolkit:NumericValidationAction /> </EventTrigger> </Entry.Triggers>
再來看 Behavior
Behavior 有兩個方法要覆寫,OnAttachedTo 和 OnDetachingFrom
OnAttachedTo - 當 Behavior 附加於 Visual Element 時被呼叫。
//通常會委派新的事件 (handler) 給物件 。
OnDetachingFrom - 要移除 OnAttachedTo 做的所有事情
//即使這件事通常只發生在程式關閉時,你還是得寫好移除的動作。
namespace Xamarin.FormsBook.Toolkit { public class NumericValidationBehavior : Behavior< Entry> { protected override void OnAttachedTo(Entry entry) { base.OnAttachedTo(entry); //委派新事件 entry.TextChanged += OnEntryTextChanged; } protected override void OnDetachingFrom(Entry entry) { base.OnDetachingFrom(entry); //移除事件 entry.TextChanged -= OnEntryTextChanged; } void OnEntryTextChanged(object sender, TextChangedEventArgs args) { //若輸入非數字,則將文字改成紅色 double result; bool isValid = Double.TryParse(args.NewTextValue, out result); ((Entry)sender).TextColor = isValid ? Color.Default : Color.Red; } } }
*要注意 Behavior<T> 會指定附加時物件的型別,本範例就是 Entry
來看 XAML 怎使用:
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms" xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml" xmlns:toolkit="clr-namespace:Xamarin.FormsBook.Toolkit;assembly=Xamarin.FormsBook.Toolkit" x:Class="BehaviorEntryValidation.BehaviorEntryValidationPage" Padding="50"> <ContentPage.Resources> <ResourceDictionary> <Style TargetType="Entry"> <!--跟 Trigger 有那麼一點像吧--> <Style.Behaviors> <toolkit:NumericValidationBehavior /> </Style.Behaviors> </Style> </ResourceDictionary> </ContentPage.Resources> <StackLayout> <Entry Placeholder="Enter a System.Double" /> <Entry Placeholder="Enter a System.Double" /> <Entry Placeholder="Enter a System.Double" /> <Entry Placeholder="Enter a System.Double" /> </StackLayout> </ContentPage>
執行結果:
因為寫在 Style 內的關係,畫面上四個 Entry 都被賦予新的 Behavior
雖然與 Trigger 比起來程式碼多了許多,
但 Behavior 給予我們更彈性的寫法甚至是建立 可綁定的屬性!!
Behavior 與可綁定屬性
在 Behavior 內,我們可以自行新增 可綁定屬性 (Bindable Property),
Bindable Property 的觀念在十一章,
//不過我沒寫,呵呵。
總之,若 XAML 要與某屬性 Binding,那個屬性就必須為 可綁定的 (Bindable)。
在 Behavior 內新增 可綁定屬性 的用意就是,當我們事件邏輯處理完後,可以把結果綁回 XAML 進行畫面上的控制。
例如底下要做的 Email 驗證,若 Entry 輸入非 Email 格式,那 Button 就不能點擊。
底下我們利用 Behavior 來實作 Email 驗證,
並加入可綁定的 IsValid 屬性:
namespace Xamarin.FormsBook.Toolkit { public class ValidEmailBehavior : Behavior{ //加入可綁定屬性的寫法 static readonly BindablePropertyKey IsValidPropertyKey = BindableProperty.CreateReadOnly("IsValid", typeof(bool), typeof(ValidEmailBehavior), false); public static readonly BindableProperty IsValidProperty = IsValidPropertyKey.BindableProperty; public bool IsValid { //可綁定屬性記得加上 SetValue 和 GetValue private set { SetValue(IsValidPropertyKey, value); } get { return (bool)GetValue(IsValidProperty); } } protected override void OnAttachedTo(Entry entry) { entry.TextChanged += OnEntryTextChanged; base.OnAttachedTo(entry); } protected override void OnDetachingFrom(Entry entry) { entry.TextChanged -= OnEntryTextChanged; base.OnDetachingFrom(entry); } void OnEntryTextChanged(object sender, TextChangedEventArgs args) { Entry entry = (Entry)sender; IsValid = IsValidEmail(entry.Text); } //判斷是否為 Email bool IsValidEmail(string strIn) { if (String.IsNullOrEmpty(strIn)) return false; try { // from https://msdn.microsoft.com/en-us/library/01escwtf(v=vs.110).aspx return Regex.IsMatch(strIn, @"^(?("")("".+?(?<!\\)""@)|(([0-9a-z]((\.(?!\.))|" + @"[-!#\$%&'\*\+/=\?\^`\{\}\|~\w])*)" + @"(?<=[0-9a-z])@))(?(\[)(\[(\d{1,3}\.){3}\d{1,3}\])|" + @"(([0-9a-z][-\w]*[0-9a-z]*\.)+[a-z0-9][\-a-z0-9]{0,22}[a-z0-9]))$", RegexOptions.IgnoreCase, TimeSpan.FromMilliseconds(250)); } catch (RegexMatchTimeoutException) { return false; } } } }
將 IsValid 綁定於 Button 的 IsEnabled:
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms" xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml" xmlns:toolkit="clr-namespace:Xamarin.FormsBook.Toolkit;assembly=Xamarin.FormsBook.Toolkit" x:Class="EmailValidationConverter.EmailValidationConverterPage" Padding="50"> <StackLayout> <StackLayout Orientation="Horizontal"> <Entry Placeholder="Enter email address" HorizontalOptions="FillAndExpand"> <!--加入 Behavior--> <Entry.Behaviors> <toolkit:ValidEmailBehavior x:Name="validEmail" /> </Entry.Behaviors> </Entry> </StackLayout> <!--綁定 IsValid--> <Button Text="Send!" FontSize="Large" HorizontalOptions="Center" IsEnabled="{Binding Source={x:Reference validEmail}, Path=IsValid}" /> </StackLayout> </ContentPage>
最後要提醒的是,
若 Behavior 內 有可綁定屬性,就不能寫在 Style 內讓大家一起共用...
必須於每個 Visual Element 加入自己的 Behavior,
原因是,
可綁定屬性是一種 狀態,而這個狀態是依據每個 Visual Element所輸入的值而有所不同,
當然不能跟其他物件一起共用那個狀態拉!
沒有留言:
張貼留言
注意:只有此網誌的成員可以留言。