January 20th, 2016

Data Binding Tips and Tricks for iOS, Android, and Windows

Utilizing data binding in Xamarin.Forms applications can greatly simplify application development by automatically synchronizing app data to the user interface with very little work. Previously, we took a look at setting up your project to begin data binding and then saw it in action in an app.

In this blog post, I’m going to explore more advanced data binding scenarios where values are formatted and converted as they are passed between source and target by the binding engine.

Control-to-Control Bindings

While data bindings are most often used to synchronize a UI with an underlying data model, they can also be defined to link properties of two controls on the same page. This is achieved by setting the BindingContext of the target object using the x:Reference markup extension, as demonstrated in the following XAML code example from the sample application:

<ContentPage xmlns="http://xamarin.com/schemas/2014/forms" xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml" x:Class="AdvancedDataBinding.RotationPage" Title="Rotation" Icon="xaml.png">
	<StackLayout Padding="0,20,0,0">
		<Label Text="Advanced Data Binding Demo" FontAttributes="Bold" HorizontalOptions="Center" />
		<Slider x:Name="slider" Maximum="360" />
		<Image Source="waterfront.jpg" BindingContext="{x:Reference slider}" 
               Rotation="{Binding Value}" VerticalOptions="CenterAndExpand" />
		<Label BindingContext="{x:Reference slider}" HorizontalOptions="Center"
               Text="{Binding Value, StringFormat='Rotation angle: {0:F0} degrees'}" />
	</StackLayout>
</ContentPage>

The Slider contains an x:Name attribute that is referenced by the two Label instances, using the x:Reference markup extension. This binding extension defines a property called Name to set to the name of the referenced element, in this case slider. However, the Name property is not explicitly required and is omitted here. The Value property of the Slider is bound to from both the Rotation property of the Image and the Text property of the Label. Therefore, as the slider is moved, the Image rotates and the Label is updated with the rotation angle, as shown in the following screenshots:

rotation

In Xamarin.Forms, bindings do not perform any implicit type conversions. However, the Binding markup extension has a StringFormat property that allows you to apply a .NET formatting string to the data. In the second Label instance, a formatting string of {0:F0} is used to display the Value property of the Slider to zero decimal places. Formatting strings must be suitable for a call to the string.Format method, and the entire formatting string is placed in single quotes to avoid the curly braces being mistaken for the braces used to delimit markup extensions.

Converters

While string formatting can be used to format the data returned from a source object, it can’t be used to perform type conversions. This is the role of value converters. A value converter is a class that allows you to change the format of data as it’s passed between source and target by the binding engine. This is achieved by the class implementing the IValueConverter interface, which requires you to implement Convert and ConvertBack methods.

The following code example shows the IntToBooleanConverter, used in the sample application, which returns a boolean value based on a comparison of two integer values:

public class IntToBooleanConverter : IValueConverter
{
	public object Convert (object value, Type targetType, object parameter, CultureInfo culture)
	{
		int minimumLength = System.Convert.ToInt32 (parameter);
		return (int)value >= minimumLength;
	}

	public object ConvertBack (object value, Type targetType, object parameter, CultureInfo culture)
	{
		throw new NotImplementedException ();
	}
}

The Convert method is called whenever a value passes from the source to the target. The value argument to Convert is the value from the source to be converted. The targetType argument is the type of the target property, and the Convert method should return an object or value that matches the targetType. The parameter argument is an optional conversion parameter that can be specified as a property to the Binding markup extension. Finally, the culture argument can be used if you need to perform a culture-specific conversion. The IntToBooleanConverter returns true if the value from the source is greater than or equal to the value of the parameter argument, otherwise it returns false.

The ConvertBack method is called whenever a value passes from the target to the source (for TwoWay or OneWayToSource bindings). For this method, the value argument is the value from the target and the targetType argument is the type of the source property. When the ConvertBack method isn’t required, it’s common to have it throw a NotImplementedException, or return null.

Similarly, the sample application also contains an IntToColorConverter, which returns one of two colors depending on a comparison of two integer values.

In XAML, value converters are usually instantiated in a ResourceDictionary and then referenced in a Binding expression by using the StaticResource markup extension. Because value converters don’t maintain state, a value converter instance can be shared amongst multiple bindings.

The following code example demonstrates the use of value converters in the sample application:

<ContentPage xmlns="http://xamarin.com/schemas/2014/forms" xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml" xmlns:local="clr-namespace:AdvancedDataBinding;assembly=AdvancedDataBinding" x:Class="AdvancedDataBinding.ConverterPage" Title="Converter" Icon="xaml.png">
	<ContentPage.Resources>
		<ResourceDictionary>
			<local:IntToBooleanConverter x:Key="intToBoolConverter" />
			<local:IntToColorConverter x:Key="intToColorConverter" />
		</ResourceDictionary>
	</ContentPage.Resources>
	<StackLayout Padding="0,20,0,0">
		<Label Text="Advanced Data Binding Demo" FontAttributes="Bold" HorizontalOptions="Center" />
		<Label Text="Enter your response (minimum 10 characters):" />
		<Editor x:Name="editor" HeightRequest="100" />
		<StackLayout Orientation="Horizontal">
			<Label Text="Number of characters:" />
			<Label Text="{Binding Source={x:Reference editor}, Path=Text.Length}" 
                   TextColor="{Binding Source={x:Reference editor}, Path=Text.Length, 
                               Converter={StaticResource intToColorConverter}, ConverterParameter=10}" />
		</StackLayout>
		<Button Text="Send" HorizontalOptions="Center" 
                IsEnabled="{Binding Source={x:Reference editor}, Path=Text.Length, 
                            Converter={StaticResource intToBoolConverter}, ConverterParameter=10}" />
	</StackLayout>
</ContentPage>

In order to reference value converters in XAML, their location must be specified with an XML namespace declaration (xmlns). Accessing classes that are local to the application PCL is usually achieved with the local prefix. The namespace declaration indicates the namespace name and the assembly containing the code.

The IntToBoolConverter is instantiated in the page’s ResourceDictionary and referenced in the Binding expression set on the IsEnabled property of the Button. It’s used to enable the Button only when a minimum of ten characters have been entered into the Editor. Similarly, the IntToColorConverter is used to set the color of the number of characters that have been entered into the Editor to green when there’s a minimum of ten characters, otherwise it sets to red. The screenshots below demonstrate this functionality:

converter-pre

converter-post

Note that if only one instance of a value converter is being used, it doesn’t need to be stored in a ResourceDictionary. Instead, it can be instantiated directly in the Binding. For more information, see From Data Bindings to MVVM.

Wrapping Up

While data bindings are most often used to synchronize a UI with an underlying data model, they can also be defined to link properties of two views on the same page. This is achieved by setting the BindingContext of the target object using the x:Reference markup extension.

In Xamarin.Forms, bindings do not perform any implicit type conversions. String formatting can be used to format data returned from a source object, and value converters can be used to change the format of data as it’s passed between source and target by the binding engine.

For more information about XAML markup extensions, see XAML Markup Extensions. For more information about data binding, see Data Binding Basics and From Data Bindings to MVVM. Xamarin University also provides a class on data binding in Xamarin.Forms.

Author

0 comments

Discussion are closed.