Turn Events into Commands with Behaviors

David Britch

Utilizing data binding in mobile apps can greatly simplify development by automatically synchronizing an app’s data to its user interface with minimal set up. Previously, we looked at the basics of data binding, and then explored some more advanced data binding scenarios where values are formatted and converted as they are passed between source and target by the binding engine. We then examined a Xamarin.Forms feature called commanding, that allows data bindings to make method calls directly to a ViewModel, such as when a button is clicked.

In this blog post, let’s explore a Xamarin.Forms feature called behaviors, which in the context of commanding, enables any Xamarin.Forms control to use data bindings to make method calls to a ViewModel.

Introduction to Behaviors

Behaviors let you add functionality to UI controls without having to subclass them. Instead, the functionality is implemented in a behavior class and attached to the control as if it was part of the control itself. Behaviors enable you to implement code that you would normally have to write as code-behind because it directly interacts with the API of the control in such a way that it can be concisely attached to the control and packaged for reuse across more than one app. They can be used to provide a full range of functionality to controls, from adding an email validator to a Entry to creating a rating control using a tap gesture recognizer.

Implementing a Behavior

The procedure for implementing a behavior is as follows:

  1. Inherit from the Behavior<T> class, where T is the type of control that the behavior should apply to.
  2. Override the OnAttachedTo method and use it to perform any set up.
  3. Override the OnDetachingFrom method to perform any clean up.
  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 the UI control. This method is used to wire up event handlers or perform another setup that’s required to support the behavior functionality. For example, you could subscribe to the ListView.ItemSelected event and execute a command when the event fires. The behavior functionality would then be implemented in the event handler for the ItemSelected event.

The OnDetachingFrom method is fired when the behavior is removed from the UI control and is used to perform any required clean up. For example, you could unsubscribe from the ListView.ItemSelected event in order to prevent memory leaks.

Consuming a Behavior

Every Xamarin.Forms control has a behavior collection to which behaviors can be added, as shown in the following code example:

<Editor>
	<Editor.Behaviors>
		<local:CustomBehavior />
	</Editor.Behaviors>
</Editor>

At runtime, the behavior will respond to interaction with the control, as per the behavior implementation.

Invoking a Command in Response to an Event

In the context of commanding, behaviors are a useful approach for connecting a control to a command. In addition, they can also be used to associate commands with controls that were not designed to interact with commands. For example, they can be used to invoke a command in response to an event firing. Therefore, behaviors address many of the same scenarios as command-enabled controls, while providing a greater degree of flexibility.

The sample application contains the ListViewSelectedItemBehavior class, that executes a command in response to the ListView.ItemSelected event firing.

Implementing Bindable Properties

In order to execute a user specified command, the ListViewSelectedItemBehavior defines two BindableProperty instances, as shown in the following code example:

public class ListViewSelectedItemBehavior : Behavior<ListView>
{
	public static readonly BindableProperty CommandProperty = 
            BindableProperty.Create ("Command", typeof(ICommand), typeof(ListViewSelectedItemBehavior), null);
	public static readonly BindableProperty InputConverterProperty = 
            BindableProperty.Create ("Converter", typeof(IValueConverter), typeof(ListViewSelectedItemBehavior), null);

	public ICommand Command {
		get { return (ICommand)GetValue (CommandProperty); }
		set { SetValue (CommandProperty, value); }
	}

	public IValueConverter Converter {
		get { return (IValueConverter)GetValue (InputConverterProperty); }
		set { SetValue (InputConverterProperty, value); }
	}
    ...
}

When this behavior is consumed by a ListView, the Command property should be data bound to an ICommand to be executed in response to the ListView.ItemSelected event firing, and the Converter property should be set to a converter that returns the SelectedItem from the ListView.

Implementing the Overrides

The ListViewSelectedItemBehavior overrides the OnAttachedTo and OnDetachingFrom methods of the Behavior<T> class, as shown in the following code example:

public class ListViewSelectedItemBehavior : Behavior<ListView>
{
    ...
	public ListView AssociatedObject { get; private set; }

	protected override void OnAttachedTo (ListView bindable)
	{
		base.OnAttachedTo (bindable);
		AssociatedObject = bindable;
		bindable.BindingContextChanged += OnBindingContextChanged;
		bindable.ItemSelected += OnListViewItemSelected;
	}

	protected override void OnDetachingFrom (ListView bindable)
	{
		base.OnDetachingFrom (bindable);
		bindable.BindingContextChanged -= OnBindingContextChanged;
		bindable.ItemSelected -= OnListViewItemSelected;
		AssociatedObject = null;
	}
    ...
}

The OnAttachedTo method subscribes to the BindingContextChanged and ItemSelected events of the attached ListView. The reasons for the subscriptions are explained in the next section. In addition, a reference to the ListView the behavior is attached to is stored in the AssociatedObject property.

The OnDetachingFrom method cleans up by unsubscribing from the BindingContextChanged and ItemSelected events.

Implementing the Behavior Functionality

The purpose of the behavior is to execute a command when the ListView.ItemSelected event fires. This is achieved in the OnListViewItemSelected method, as shown in the following code example:

public class ListViewSelectedItemBehavior : Behavior<ListView>
{
    ...
	void OnBindingContextChanged (object sender, EventArgs e)
	{
		OnBindingContextChanged ();
	}

	void OnListViewItemSelected (object sender, SelectedItemChangedEventArgs e)
	{
		if (Command == null) {
			return;
		}

		object parameter = Converter.Convert (e, typeof(object), null, null);
		if (Command.CanExecute (parameter)) {
			Command.Execute (parameter);
		}
	}

	protected override void OnBindingContextChanged ()
	{
		base.OnBindingContextChanged ();
		BindingContext = AssociatedObject.BindingContext;
	}
}

The OnListViewItemSelected method, which is executed in response to the ListView.ItemSelected event firing, first executes the converter referenced through the Converter property, which returns the SelectedItem from the ListView. The method then executes the data bound command, referenced through the Command property, passing in the SelectedItem as a parameter to the command.

The OnBindingContextChanged override, which is executed in response to the ListView.BindingContextChanged event firing, sets the BindingContext of the behavior to the BindingContext of the control the behavior is attached to. This ensures that the behavior can bind to and execute the command that’s specified when the behavior is consumed.

Consuming the Behavior

The ListViewSelectedItemBehavior is attached to the ListView.Behaviors collection, as shown in the following code example:

<ListView ItemsSource="{Binding People}">
	<ListView.Behaviors>
		<local:ListViewSelectedItemBehavior Command="{Binding OutputAgeCommand}" 
            Converter="{StaticResource SelectedItemConverter}" />
	</ListView.Behaviors>
</ListView>
<Label Text="{Binding SelectedItemText}" />

The Command property of the behavior is data bound to the OutputAgeCommand property of the associated ViewModel, while the Converter property is set to the SelectedItemConverter instance, which returns the SelectedItem of the ListView from the SelectedItemChangedEventArgs.

The result of the behavior being consumed is that when the ListView.ItemSelected event fires due to an item being selected in the ListView, the OutputAgeCommand is executed, which updates the SelectedItemText property that the Label binds to. The following screenshots show this:

ExecuteCommand

Generalizing the Behavior

It’s possible to generalize the ListViewSelectedItemBehavior so that it can be used by any Xamarin.Forms control, and so that it can execute a command in response to any event firing, as shown in the following code example:

<ListView ItemsSource="{Binding People}">
	<ListView.Behaviors>
		<local:EventToCommandBehavior EventName="ItemSelected" Command="{Binding OutputAgeCommand}" 
            Converter="{StaticResource SelectedItemConverter}" />
	</ListView.Behaviors>
</ListView>
<Label Text="{Binding SelectedItemText}" />

For more information, see the EventToCommandBehavior class in the sample application.

Wrapping Up Behaviors

In the context of commanding, behaviors are a useful approach for connecting a control to a command. In addition, they can also be used to associate commands with controls that were not designed to interact with commands. For example, they can be used to invoke a command in response to an event firing. Therefore, behaviors address many of the same scenarios as command-enabled controls, while providing a greater degree of flexibility.

For more information about behaviors, see our Working with Behaviors document.

0 comments

Discussion is closed.

Feedback usabilla icon