Xamarin Forms Binding

Binding, in the most common context, is the process of mapping a property on a Page, to a property in a ViewModel. In Xamarin Forms terms, the Page is a BindableObject and the BindableObject has a BindingContext, which would be the ViewModel. Most UI Elements on the Page, will also be a BindableObject, inheriting their BindingContext from their parent. Binding in Xamarin Forms is built in to the framework.

Markup Extension

First lets start with looking at how to define a binding in a page. If we look at a Label, and the Text property, we can bind this to a property.

<Label Text="{Binding MyProperty}" />

But where is this property defined? It will be a public property in our BindingContext, in this example, the ViewModel. This

public class MyViewModel
{
    public string MyProperty { get; set; } = "My Label Text";
}

Then set the BindingContext of the Page. In your Page constructor add:

this.BindingContext = new MyViewModel();

Now your label on the Page will display, My Label Text.

INotifyPropertyChanged

Moving forward, this works well if you never want to change the property again, but now we want to keep a track of what is happening in the ViewModel, and update the Page whenever the ViewModel property changes. To implement this we need to use INotifyPropertyChanged. Implementing this allows the Binding Engine, inside Xamarin Forms, to detect when a change to a property has been made, and then make the required changes in the Page.

When you add INotifyPropertyChanged to your ViewModel, you will need to implement the event below.

public class MyViewModel: INotifyPropertyChanged
{
    public event PropertyChangedEventHandler PropertyChanged;
    public void OnPropertyChanged([CallerMemberName] string name = "")
    {
        PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(name));
    }
}

You will also notice, that I implemented a public method, to call PropertyChanged, with the PropertyName that has changed. If we go to our property, we now need to update it, to raise this event, every time the property is changed.

private string _myProperty;
public string MyProperty
{
    get {
        return _myProperty;
    }
    set {
        if (_myProperty != value)
        {
            _myProperty = value;
            OnPropertyChanged();
        } 
    }
}

When this property is changed, it will now raise an event. The event will be picked up by the BindingEngine, and copy the value from this property to the Label. It is recommended that you put the OnPropertyChanged and event, inside a base class and inherit from it, to avoid writing the same code for each ViewModel. You also have the option of using an MVVM framework. MVVM frameworks, normally implement a BaseViewModel that has these defined for you.

Binding Modes

By default, Xamarin Forms will setup the binding so that it goes from the BindingContext (ViewModel) to the BindableObject (Page). This is called OneWay binding.

However, there are two other options you can choose from. OneWayToSource is another option, and you can think of it as the reverse of OneWay binding.

Finally there is TwoWay binding. This allows updates on the BindableObject or the BindingContext to update each other. This is where the check to ensure that it is not setting the property to the same value is a good idea, otherwise you may end up in a infinite binding loop. TwoWay binding is used when you want to record the users input, and also set it from the BindingContext, for example, an Entry control.

Formatter

Sometimes what you want to display is not exactly how the data is stored. For example if we wanted to format a double and add a percentage to the end, and you have bound the label to a double. For this we can simply use a formatter. You can use this to format types such as Doubles and DateTimes. If MyProperty was a Double, we could do this, to format it.

<Label Text="{Binding MyProperty, StringFormat='{0:N2}%'}" />

The Binding Engine, will use this formatter, before applying the value to the control.

ValueConverter

If we want to go a step further than formatting, we need to use a ValueConverter. A ValueConverter can be seen as a translation process. Maybe the control property you are binding to, doesn’t exactly match the type of the property in the BindingContext. When this happens, a ValueConverter, will convert the value into something the target can handle. One of the most common you might see around is an InverseBooleanConverter, where you want to bind to a boolean in the ViewModel, but you need the opposite of it’s value.

public class InverseBooleanConverter : IValueConverter
{
    public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
    {
        if (targetType != typeof(bool))
            throw new InvalidOperationException("The target must be a boolean");

        return !(bool)value;
    }
    public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
    {
        // Optional: throw new NotSupportedException();
    }
}

If you are using OneWay binding, you don’t need to worry about the ConvertBack, however you will need to implement it if you are using any of the other Binding Modes.

Applying the value converter requires you to define it in the resource dictionary.

<ContentPage xmlns:converters="clr-namespace:MyApp.NamespaceConvertersAreIn" ... >
    <ContentPage.Resources>
        <ResourceDictionary>
            <converters:InverseBooleanConverter x:Key="InverseBooleanConverter"/>
        </ResourceDictionary>
    </ContentPage.Resources>

Then apply it to the binding.

<Label IsVisible="{Binding IsHidden, Converter={StaticResource InverseBooleanConverter}}" />

If we have the property IsHidden, when it’s true you want to hide the label. Hence we need to convert it to the opposite, to bind to IsVisible.

 

Microsoft MVP | Xamarin MVP | Xamarin Certified Developer |
Exrin MVVM Framework | Xamarin Forms Developer | Melbourne, Australia

Related Posts