Xamarin.Forms 行为是通过从 Behavior 或 Behavior<T> 类派生来创建的。 本文演示如何创建和使用 Xamarin.Forms 行为。
概述
创建 Xamarin.Forms 行为的过程如下所示:
- 创建一个继承自 Behavior或Behavior<T>类的类,其中T是施加该行为的控件类型。
- 重写 OnAttachedTo方法以执行任何所需设置。
- 重写 OnDetachingFrom方法以执行任何所需清理。
- 实现行为的核心功能。
这将导致以下代码示例所示的结构:
public class CustomBehavior : Behavior<View>
{
    protected override void OnAttachedTo (View bindable)
    {
        base.OnAttachedTo (bindable);
        // Perform setup
    }
    protected override void OnDetachingFrom (View bindable)
    {
        base.OnDetachingFrom (bindable);
        // Perform clean up
    }
    // Behavior implementation
}
OnAttachedTo 方法在行为附加到控件后立即触发。 此方法接收对其附加的控件的引用,并可用于注册事件处理程序或执行支持行为功能所需的其他设置。 例如,你可以订阅控件上的事件。 然后,行为功能将在事件的事件处理程序中实现。
当行为从控件中移除时,将触发 OnDetachingFrom 方法。 此方法接收对其附加的控件的引用,并用于执行任何所需的清理。 例如,可以取消订阅控件上的事件,以防止内存泄漏。
然后,可以通过将其附加到相应控件的 Behaviors 集合来使用该行为。
创建 Xamarin.Forms 行为
示例应用程序演示一个 NumericValidationBehavior,并用红色突出显示用户输入到 Entry 控件的值(如果该值不是 double)。 此行为如下面的代码示例所示:
public class NumericValidationBehavior : Behavior<Entry>
{
    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)
    {
        double result;
        bool isValid = double.TryParse (args.NewTextValue, out result);
        ((Entry)sender).TextColor = isValid ? Color.Default : Color.Red;
    }
}
NumericValidationBehavior 派生自 Behavior<T> 类,其中 T 是 Entry。 OnAttachedTo 方法注册 TextChanged 事件的事件处理程序,并使用 OnDetachingFrom 方法注销 TextChanged 事件以防止内存泄漏。 该行为的核心功能由 OnEntryTextChanged 方法提供,该方法将用户输入的值解析为 Entry,如果该值不是 double,则将 TextColor 属性设置为红色。
注意
Xamarin.Forms 不会设置行为的 BindingContext,因为可以通过样式共享行为并将其应用于多个控件。
使用 Xamarin.Forms 行为
每个 Xamarin.Forms 控件都有一个 Behaviors 集合,其中可以添加一个或多个行为,如以下 XAML 代码示例所示:
<Entry Placeholder="Enter a System.Double">
    <Entry.Behaviors>
        <local:NumericValidationBehavior />
    </Entry.Behaviors>
</Entry>
下面的代码示例介绍了 C# 中的等效 Entry:
var entry = new Entry { Placeholder = "Enter a System.Double" };
entry.Behaviors.Add (new NumericValidationBehavior ());
在运行时,根据行为实现,行为将响应与控件的交互。 以下屏幕截图演示了响应无效输入的行为:
注意
行为是为特定的控件类型(或者可以应用于许多控件的超类)编写的,它们只应添加到兼容的控件中。 试图将行为附加到不兼容控件将引发异常。
使用具有样式的 Xamarin.Forms 行为
行为也可以通过显式或隐式样式使用。 但是,不能创建设置控件的 Behaviors 属性的样式,因为该属性只读。 解决方案是向行为类添加附加属性,以控制添加和删除行为。 过程如下:
- 将附加属性添加到行为类中,以控制将附加行为的控件添加行为和删除行为。 确保附加的属性注册 propertyChanged委托,该委托将在属性值更改时执行。
- 为附加属性创建 staticgetter 和 setter。
- 在 propertyChanged委托中实现逻辑以添加和删除行为。
下面的代码示例显示了一个附加属性,用于控制添加和删除 NumericValidationBehavior:
public class NumericValidationBehavior : Behavior<Entry>
{
    public static readonly BindableProperty AttachBehaviorProperty =
        BindableProperty.CreateAttached ("AttachBehavior", typeof(bool), typeof(NumericValidationBehavior), false, propertyChanged: OnAttachBehaviorChanged);
    public static bool GetAttachBehavior (BindableObject view)
    {
        return (bool)view.GetValue (AttachBehaviorProperty);
    }
    public static void SetAttachBehavior (BindableObject view, bool value)
    {
        view.SetValue (AttachBehaviorProperty, value);
    }
    static void OnAttachBehaviorChanged (BindableObject view, object oldValue, object newValue)
    {
        var entry = view as Entry;
        if (entry == null) {
            return;
        }
        bool attachBehavior = (bool)newValue;
        if (attachBehavior) {
            entry.Behaviors.Add (new NumericValidationBehavior ());
        } else {
            var toRemove = entry.Behaviors.FirstOrDefault (b => b is NumericValidationBehavior);
            if (toRemove != null) {
                entry.Behaviors.Remove (toRemove);
            }
        }
    }
    ...
}
NumericValidationBehavior 类包含带有 static getter 和 setter 且名为 AttachBehavior 的附加属性,该属性控制将附加行为的控件添加和删除行为。 该附加属性注册属性值更改时执行的 OnAttachBehaviorChanged 方法。 该方法根据 AttachBehavior 附加属性的值向控件添加或移除行为。
下面的代码示例显示使用 AttachBehavior 附加属性的 NumericValidationBehavior 的显式样式,该样式可应用于 Entry 控件:
<Style x:Key="NumericValidationStyle" TargetType="Entry">
    <Style.Setters>
        <Setter Property="local:NumericValidationBehavior.AttachBehavior" Value="true" />
    </Style.Setters>
</Style>
Style 通过使用 StaticResource 标记扩展将其 Style 属性设置为 Style 实例使其可应用于 Entry 控件,如以下代码示例所示:
<Entry Placeholder="Enter a System.Double" Style="{StaticResource NumericValidationStyle}">
有关样式的详细信息,请参阅 样式。
注意
虽然可以向 XAML 中设置或查询的行为添加可绑定属性,但如果你确实创建了有状态的行为,则这些行为不应该在 ResourceDictionary 的Style 中的控件之间共享。
从控件中删除行为
当从控件中删除某个行为时,将触发 OnDetachingFrom 方法,该方法用于执行任何所需的清理,例如取消对事件的订阅,以防止内存泄漏。 但是,除非控件的 Behaviors 集合被 Remove 或 Clear 方法修改,否则行为不会从控件中隐式删除。 以下代码示例演示了如何从控件的 Behaviors 集合中删除特定的行为:
var toRemove = entry.Behaviors.FirstOrDefault (b => b is NumericValidationBehavior);
if (toRemove != null) {
    entry.Behaviors.Remove (toRemove);
}
或者,可以清除控件的 Behaviors 集合,如下面的代码示例所示:
entry.Behaviors.Clear();
此外,请注意,当从导航堆栈中弹出页面时,行为不会从控件中隐式删除。 相反,必须在页面超出范围之前显式删除它们。
总结
本文演示如何创建和使用 Xamarin.Forms 行为。 Xamarin.Forms 行为由 Behavior 或 Behavior<T> 类派生创建而成。
