Xamarin.Forms Behaviors

Adding functionality to controls without subclassing

PDF for offline use
Sample Code:
Related APIs:

Let us know how you feel about this

Translation Quality


0/250

last updated: 2016-04

Xamarin.Forms behaviors are created by deriving from the Behavior or Behavior<T> class. This article demonstrates how to create and consume Xamarin.Forms behaviors.

Overview

The process for creating a Xamarin.Forms behavior is as follows:

  1. Create a class that inherits from the Behavior or Behavior<T> class, where T is the type of the control to which the behavior should apply.
  2. Override the OnAttachedTo method to perform any required setup.
  3. Override the OnDetachingFrom method to perform any required cleanup.
  4. Implement the core functionality of the behavior.

This results in the structure shown in the following code example:

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
}

The OnAttachedTo method is fired immediately after the behavior is attached to a control. This method receives a reference to the control to which it is attached, and can be used to register event handlers or perform other setup that's required to support the behavior functionality. For example, you could subscribe to an event on a control. The behavior functionality would then be implemented in the event handler for the event.

The OnDetachingFrom method is fired when the behavior is removed from the control. This method receives a reference to the control to which it is attached, and is used to perform any required cleanup. For example, you could unsubscribe from an event on a control in order to prevent memory leaks.

The behavior can then be consumed by attaching it to the Behaviors collection of the appropriate control.

Creating a Xamarin.Forms Behavior

The sample application demonstrates a NumericValidationBehavior, which highlights the value entered by the user into an Entry control in red, if it's not a double. The behavior is shown in the following code example:

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;
    }
}

The NumericValidationBehavior derives from the Behavior<T> class, where T is an Entry. The OnAttachedTo method registers an event handler for the TextChanged event, with the OnDetachingFrom method de-registering the TextChanged event in order to prevent memory leaks. The core functionality of the behavior is provided by the OnEntryTextChanged method, which parses the value entered by the user into the Entry, and sets the TextColor property to red if the value isn't a double.

Xamarin.Forms does not set the BindingContext of a behavior, because behaviors can be shared and applied to multiple controls through styles.

Consuming a Xamarin.Forms Behavior

Every Xamarin.Forms control has a Behaviors collection, to which one or more behaviors can be added, as demonstrated in the following XAML code example:

<Entry Placeholder="Enter a System.Double">
    <Entry.Behaviors>
        <local:NumericValidationBehavior />
    </Entry.Behaviors>
</Entry>

The equivalent Entry in C# is shown in the following code example:

var entry = new Entry { Placeholder = "Enter a System.Double" };
entry.Behaviors.Add (new NumericValidationBehavior ());

At runtime the behavior will respond to interaction with the control, according to the behavior implementation. The following screenshots demonstrate the behavior responding to invalid input:

Behaviors are written for a specific control type (or a superclass that can apply to many controls), and they should only be added to a compatible control. Attempting to attach a behavior to an incompatible control will result in an exception being thrown.

Consuming a Xamarin.Forms Behavior with a Style

Behaviors can also be consumed by an explicit or implicit style. However, creating a style that sets the Behaviors property of a control is not possible because the property is read-only. The solution is to add an attached property to the behavior class that controls adding and removing the behavior. The process is as follows:

  1. Add an attached property to the behavior class that will be used to control the addition or removal of the behavior to the control to which the behavior will attached. Ensure that the attached property registers a propertyChanged delegate that will be executed when the value of the property changes.
  2. Create a static getter and setter for the attached property.
  3. Implement logic in the propertyChanged delegate to add and remove the behavior.

The following code example shows an attached property that controls adding and removing the 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);
            }
        }
    }
    ...
}

The NumericValidationBehavior class contains an attached property named AttachBehavior with a static getter and setter, which controls the addition or removal of the behavior to the control to which it will be attached. This attached property registers the OnAttachBehaviorChanged method that will be executed when the value of the property changes. This method adds or removes the behavior to the control, based on the value of the AttachBehavior attached property.

The following code example shows an explicit style for the NumericValidationBehavior that uses the AttachBehavior attached property, and which can be applied to Entry controls:

<Style x:Key="NumericValidationStyle" TargetType="Entry">
    <Style.Setters>
        <Setter Property="local:NumericValidationBehavior.AttachBehavior" Value="true" />
    </Style.Setters>
</Style>

The Style can be applied to an Entry control by setting its Style property to the Style instance using the StaticResource markup extension, as demonstrated in the following code example:

<Entry Placeholder="Enter a System.Double" Style="{StaticResource NumericValidationStyle}">

For more information about styles, see Styles.

While you can add bindable properties to a behavior that is set or queried in XAML, if you do create behaviors that have state they should not be shared between controls in a Style in a ResourceDictionary.

Removing a Behavior from a Control

The OnDetachingFrom method is fired when a behavior is removed from a control, and is used to perform any required cleanup such as unsubscribing from an event in order to prevent a memory leak. However, behaviors are not implicitly removed from controls unless the control's Behaviors collection is modified by a Remove or Clear method. The following code example demonstrates removing a specific behavior from a control's Behaviors collection:

var toRemove = entry.Behaviors.FirstOrDefault (b => b is NumericValidationBehavior);
if (toRemove != null) {
    entry.Behaviors.Remove (toRemove);
}

Alternatively, the control's Behaviors collection can be cleared, as demonstrated in the following code example:

entry.Behaviors.Clear();

In addition, note that behaviors are not implicitly removed from controls when pages are popped from the navigation stack. Instead, they must be explicitly removed prior to pages going out of scope.

Summary

This article demonstrated how to create and consume Xamarin.Forms behaviors. Xamarin.Forms behaviors are created by deriving from the Behavior or Behavior<T> class.

Xamarin Workbook

If it's not already installed, install the Xamarin Workbooks app first. The workbook file should download automatically, but if it doesn't, just click to start the workbook download manually.