Monday, 29 February 2016

Xamarin.Forms Behaviors: EventHandlerBehavior and InvokeCommandAction

Previously, I introduced my Behaviors Library for Xamarin.Forms, which can be downloaded from GitHub and NuGet. Behaviors let you add functionality to 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.

In the context of commanding, behaviors are a useful approach for connecting a control to a command. In addition, they can be used to associate commands with controls that weren’t designed to interacts 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 Behaviors Library for Xamarin.Forms has the notion of behaviors and actions. A behavior is attached to a control and listens for something to happen, such as an event firing. When the “something” happens, it triggers one or more actions, such as invoking a command. Actions are invoked by behaviors and executed on a selected control.

In this blog post, I’ll demonstrate using the EventHandlerBehavior and InvokeCommandAction classes to invoke one or more commands when an event fires.

Invoking a Command when an Event Fires

The EventHandlerBehavior class listens for a specified event to occur, and executes one or more actions in response. It requires you to set an EventName property to the event that you want the behavior to listen to, and an Actions property to one or more actions that should be executed in response to the event firing.

The InvokeCommandAction class executes a specified ICommand when invoked. It requires you to set a Command property to an ICommand instance, and CommandParameter and Converter properties can be optionally set. The CommandParameter property should be set to an object instance, with the Converter property being set to an instance of a class that implements IValueConverter. The ICommand specified in the Command property will then be executed, with the CommandParameter and Converter values being used if specified.

The following code shows an example of using the EventHandlerBehavior to invoke two commands:

<ListView ItemsSource="{Binding People}"> <ListView.Behaviors> <behaviors:EventHandlerBehavior EventName="ItemSelected"> <behaviors:InvokeCommandAction Command="{Binding ItemSelectedCommand}" Converter="{StaticResource SelectedItemConverter}" /> <behaviors:InvokeCommandAction Command="{Binding OutputAgeCommand}" Converter="{StaticResource SelectedItemConverter}" /> </behaviors:EventHandlerBehavior> </ListView.Behaviors> </ListView>

When the ListView.ItemSelected event fires, the ItemSelectedCommand and OutputAgeCommand are sequentially executed. The InvokeCommandAction class expects to find the ICommand instances on the BindingContext of the attached object, (and the BindingContext may have been set by a parent element). The Converter property of each InvokeCommandAction instance is set to the SelectedItemConverter instance, which returns the SelectedItem of the ListView from the SelectedItemChangedEventArgs. Note that the Actions property of the EventHandlerBehavior is set indirectly by creating the InvokeCommandAction instances as children of the EventHandlerBehavior instance.

The advantage of using the EventHandlerBehavior and InvokeCommandAction classes is that that commands can be associated with controls that weren’t designed to interact with commands, removing boiler-plate event handling code from code-behind files.

The sample application that this code comes from can be downloaded from GitHub.

Summary

The EventHandlerBehavior class listens for a specified event to occur, and executes one or more actions in response. The InvokeCommandAction class executes a specified ICommand when invoked. By using these two classes, commands can be associated with controls that weren’t designed to interact with commands, removing boiler-plate event handling code from code-behind files.

2 comments:

  1. Bug: I used CommandParameter instead of Converter for passing selected item.It passes previously selected item to command method

    ReplyDelete
    Replies
    1. A potential problem with using CommandParameter is that it *may* introduce a UI dependency into your ViewModel. To purists in the MVVM world, that would be bad.

      Delete