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:
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:
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.
0 comments