Friday, 8 June 2018

Xamarin.Forms Behaviors: EventHandlerBehavior and the SourceObject

I previously mentioned that I’d published v1.4 of my Behaviors library, and that it included some new functionality. In my last blog post I looked at the GoToStateAction, which is the main item of new functionality. Another new item is the SourceObject property that now exists on the EventHandlerBehavior class.

Prior to this addition, to use the EventHandlerBehavior you’d set the EventName property to the event that you want the behavior to listen to, and the EventHandlerBehavior would automatically look for this event on the VisualElement the behavior is attached to. The following XAML shows an example of this syntax:

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

Here, when the ListView.ItemSelected event fires, the ItemSelectedCommand and OutputAgeCommand are sequentially executed. To stress the point again, the EventHandlerBehavior automatically looks for the ItemSelected event on the VisualElement the behavior is attached to – in this case, the ListView.

Introducing the SourceObject Property

In v1.4 of the Behaviors library, the EventHandlerBehavior has the following properties:

  • EventName – the name of the event to listen to, which must exist on the SourceObject.
  • (optional) SourceObject – the object on which the behavior should listen for the event specified by the EventName property. If not provided, the behavior will default to listening for the event on the VisualElement the behavior is attached to.
  • Actions – one of more actions that should be executed in response to the event firing. However, this property is typically set indirectly by specifying the action instances (InvokeCommandAction, SetPropertyAction etc.) as children of the EventHandlerBehavior instance.

By making the SourceObject property optional, and by defaulting it to listening for the event on the VisualElement the behavior is attached to, backwards compatibility with existing codebases is ensured.

The following code example shows an example of specifying the SourceObject property:

<ListView x:Name="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> <Label x:Name="itemSelectedLabel"> <Label.Behaviors> <behaviors:EventHandlerBehavior EventName="ItemSelected" SourceObject="{x:Reference listView}"> <behaviors:SetPropertyAction TargetObject="{x:Reference itemSelectedLabel}" PropertyName="Text" Value="Item selected in ListView." /> </behaviors:EventHandlerBehavior> </Label.Behaviors> </Label>

As before, when the ListView.ItemSelected event fires, the ItemSelectedCommand and OutputAgeCommand are sequentially executed. Here, because the first EventHandlerBehavior instance doesn’t specify a SourceObject, the behavior automatically looks for the ItemSelected event on the VisualElement the behavior is attached to – in this case, the ListView.

The EventHandlerBehavior instance that’s attached to the Label also listens for the ItemSelected event on the ListView, even though the behavior is attached to a Label. This is achieved by specifying the SourceObject as a reference to the ListView. Therefore, when the ListView.ItemSelected event fires, the SetPropertyAction instance updates the Label.Text property with the text specified by the Value property. Note that this example is completely contrived. It would be simpler to just move the SetPropertyAction instance to be a child of the first EventHandlerBehavior instance and remove the behavior instance from the Label (only one EventHandlerBehavior instance in the XAML then, instead of two). However, it illustrates that it’s now possible to specify an EventHandlerBehavior that listens for events on objects other than the VisualElement the behavior is attached to. This makes it possible to attach an EventHandlerBehavior instance to a VisualElement that the actions operate on, which can aid code readability.

Summary

The EventHandlerBehavior now has a SourceObject property that can be set to the object on which the behavior should listen for the event specified by the EventName property. If not provided, the EventHandlerBehavior will default to the VisualElement the behavior is attached to.

The sample application that this code comes from can be downloaded from GitHub, and the Behaviors library can be found on NuGet.

No comments:

Post a Comment