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.

Wednesday, 24 February 2016

Behaviours Library for Xamarin.Forms

Back in January I wrote a series of blog posts for the Xamarin blog. This included a post on Turning Events into Commands with Behaviors. As part of that blog post I developed a ListViewSelectedItemBehavior, for executing a command when the ListView.ItemSelected event fires. Then at the end of the blog post I mentioned that I’d generalised the ListViewSelectedItemBehavior into an EventToCommandBehavior that could be used to execute a command in response to any event firing.

This got me thinking about how I used to use behaviours when I was developing using Microsoft’s XAML. There, behaviours are attached to a control and listen for something to happen. This something would typically be an event firing or data changing. When the “something” happens, it triggers one or more Actions. Actions are invoked by Behaviours and execute on a selected control. Typical Actions included invoking a command, invoking a method, setting a property etc. These behaviours and actions were made available through the Blend SDK.

I took my EventToCommandBehavior implementation and was able to refactor it into an EventHandlerBehavior and an InvokeCommandAction. This meant I was able to invoke multiple commands in response to an event firing, as demonstrated in the following code example:

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

I then started thinking about other Behaviours and Actions that I commonly used from the Blend SDK, and after realising how much I missed them in Xamarin.Forms, I decided to implement them. The result is my Behaviors for Xamarin.Forms library.

Introducing Behaviors for Xamarin.Forms

Behaviors for Xamarin.Forms is a PCL I’ve created that can be consumed by Xamarin.Forms applications. It contains the following Behaviours and Actions:

Behaviours

  • EventHandlerBehavior – listens for a specified event to occur, and executes one or more Actions in response.
  • DataChangedBehavior – listens for the bound data to meet a specified condition, and executes one or more Actions in response.

Actions

  • InvokeCommandAction – executes a specified ICommand when invoked.
  • InvokeMethodAction – executes a method on a specified object when invoked.
  • SetPropertyAction – changes a specified property to a specified value.

Please note that the library is something I’ve created in my spare time, and isn’t an official Xamarin release. It’s open source, and is available on GitHub, and a NuGet package can be found here. Note that the NuGet package has a dependency of >= Xamarin.Forms 2.0.1.6505.

Scenarios

The library supports scenarios such as:

  • Invoking commands when an event fires, or when data changes.
  • Invoking methods (View or ViewModel) when an event fires, or when data changes.
  • Setting properties (View or ViewModel) when an event fires, or when data changes.

For examples of these scenarios, see the accompanying sample application that executes Actions against Views and ViewModels.

The result of using the library is that you can eliminate lots of boiler plate C# code, instead moving it to XAML.

Wrapping Up

Behaviors for Xamarin.Forms is a PCL library that can be used by Xamarin.Forms applications to eliminate lots of boiler plate C# code, instead moving it to XAML.

Over the coming weeks I’ll publish blog posts that explore each Behaviour and Action, explaining how they work, and any limitations.

Questions? Problems? Thoughts? Suggestions? Then drop me a line.