创建 Xamarin.Forms 行为

Xamarin.Forms 行为是通过从 Behavior 或 Behavior<T> 类派生来创建的。 本文演示如何创建和使用 Xamarin.Forms 行为。

概述

创建 Xamarin.Forms 行为的过程如下所示:

  1. 创建一个继承自 BehaviorBehavior<T> 类的类,其中 T 是施加该行为的控件类型。
  2. 重写 OnAttachedTo 方法以执行任何所需设置。
  3. 重写 OnDetachingFrom 方法以执行任何所需清理。
  4. 实现行为的核心功能。

这将导致以下代码示例所示的结构:

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> 类,其中 TEntryOnAttachedTo 方法注册 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 行为的示例应用程序

注意

行为是为特定的控件类型(或者可以应用于许多控件的超类)编写的,它们只应添加到兼容的控件中。 试图将行为附加到不兼容控件将引发异常。

使用具有样式的 Xamarin.Forms 行为

行为也可以通过显式或隐式样式使用。 但是,不能创建设置控件的 Behaviors 属性的样式,因为该属性只读。 解决方案是向行为类添加附加属性,以控制添加和删除行为。 过程如下:

  1. 将附加属性添加到行为类中,以控制将附加行为的控件添加行为和删除行为。 确保附加的属性注册 propertyChanged 委托,该委托将在属性值更改时执行。
  2. 为附加属性创建 static getter 和 setter。
  3. 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 中设置或查询的行为添加可绑定属性,但如果你确实创建了有状态的行为,则这些行为不应该在 ResourceDictionaryStyle 中的控件之间共享。

从控件中删除行为

当从控件中删除某个行为时,将触发 OnDetachingFrom 方法,该方法用于执行任何所需的清理,例如取消对事件的订阅,以防止内存泄漏。 但是,除非控件的 Behaviors 集合被 RemoveClear 方法修改,否则行为不会从控件中隐式删除。 以下代码示例演示了如何从控件的 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 行为由 BehaviorBehavior<T> 类派生创建而成。