Note
Access to this page requires authorization. You can try signing in or changing directories.
Access to this page requires authorization. You can try changing directories.
Note
This book was published in the spring of 2016, and has not been updated since then. There is much in the book that remains valuable, but some of the material is outdated, and some topics are no longer entirely correct or complete.
Programmers often find themselves writing event handlers that detect when a property of one object has changed, and use that to change the value of a property in another object. This process can be automated with the technique of data binding. Data bindings are usually defined in XAML and become part of the definition of the user interface.
Very often, these data bindings connect user-interface objects to underlying data. This is a technique that is explored more in Chapter 18. MVVM. However, data bindings can also connect two or more user-interface elements. Most of the early examples of data binding in this chapter demonstrate this technique.
Binding basics
Several properties, methods, and classes are involved in data binding:
- The
Bindingclass derives fromBindingBaseand encapsulates many characteristics of a data binding - The
BindingContextproperty is defined by theBindableObjectclass - The
SetBindingmethod is also defined by theBindableObjectclass - The
BindableObjectExtensionsclass defines three additionalSetBindingmethods
The following two classes support XAML markup extensions for bindings:
BindingExtensionsupports theBindingmarkup extensionReferenceExtensionsupports thex:Referencemarkup extension
Two interfaces are involved in data binding:
INotifyPropertyChangedin theSystem.ComponentModelnamespace is for implementing notification when a property changesIValueConverteris used to define small classes that convert values from one type to another in data bindings
A data binding connects two properties of the same object, or (more commonly) two different objects. These two properties are referred to as the source and the target. Generally, a change in the source property causes a change to occur in the target property, but sometimes the direction is reversed. Regardless:
- the target property must be backed by a
BindableProperty - the source property generally is a member of a class that implements
INotifyPropertyChanged
A class that implements INotifyPropertyChanged fires a PropertyChanged event when a property changes value. BindableObject implements INotifyPropertyChanged and automatically fires a PropertyChanged event when a property backed by a BindableProperty changes values, but you can write your own classes that implement INotifyPropertyChanged without deriving from BindableObject.
Code and XAML
The OpacityBindingCode sample demonstrates how to set a data binding in code:
- The source is the
Valueproperty of aSlider - The target is the
Opacityproperty of aLabel
The two objects are connected by setting the BindingContext of the Label object to the Slider object. The two properties are connected by calling a SetBinding extension method on the Label referencing the OpacityProperty bindable property and the Value property of the Slider expressed as a string.
Manipulating the Slider then causes the Label to fade in and out of view.
The OpacityBindingXaml is the same program with the data binding set in XAML. The BindingContext of the Label is set to an x:Reference markup extension referencing the Slider, and the Opacity property of the Label is set to the Binding markup extension with its Path property referencing the Value property of the Slider.
Source and BindingContext
The BindingSourceCode sample shows an alternative approach in code. A Binding object is created by setting the Source property to the Slider object and the Path property to "Value". The SetBinding method of BindableObject is then called on the Label object.
The Binding constructor could also have been used to define the Binding object.
The BindingSourceXaml sample shows the comparable technique in XAML. The Opacity property of the Label is set to a Binding markup extension with Path set to the Value property and Source set to an embedded x:Reference markup extension.
In summary, there are two ways to reference the binding source object:
- Through the
BindingContextproperty of the target - Through the
Sourceproperty of theBindingobject itself
If both are specified, the second takes precedence. The advantage of the BindingContext is that it is propagated through the visual tree. This is very handy if multiple target properties are bound to the same source object.
The WebViewDemo program demonstrates this technique with the WebView element. Two Button elements for navigating backwards and forwards inherit a BindingContext from their parent that references the WebView. The IsEnabled properties of the two buttons then have simple Binding markup extensions that target the button IsEnabled properties based on the settings of the CanGoBack and CanGoForward read-only properties of the WebView.
The binding mode
Set the Mode property of Binding to a member of the BindingMode enumeration:
OneWayso that changes in the source property affect the targetOneWayToSourceso that changes in the target property affect the sourceTwoWayso that changes in the source and target affect each otherDefaultto use theDefaultBindingModespecified when the targetBindablePropertywas created. If none was specified, the default isOneWayfor normal bindable properties, andOneWayToSourcefor read-only bindable properties.
Note
The BindingMode enumeration now also includes OnTime for applying a binding only when the binding context changes and not when the source property changes.
Properties that are likely to be the targets of data bindings in MVVM scenarios generally have a DefaultBindingMode of TwoWay. These are:
Valueproperty ofSliderandStepperIsToggledproperty ofSwitchTextproperty ofEntry,Editor, andSearchBarDateproperty ofDatePickerTimeproperty ofTimePicker
The BindingModes sample demonstrates the four binding modes with a data binding where the target is the FontSize property of a Label and the source is the Value property of a Slider. This allows each Slider to control the font size of the corresponding Label. But the Slider elements are not initialized because the DefaultBindingMode of the FontSize property is OneWay.
The ReverseBinding sample sets the bindings on the Value property of the Slider referencing the FontSize property of each Label. This appears to be backwards, but it works better in initialzing the Slider elements because the Value property of the Slider has a DefaultBindingMode of TwoWay.
This is analogous to how bindings are defined in MVVM, and you'll use this type of binding frequently.
String formatting
When the target property is of type string, you can use the StringFormat property defined by BindingBase to convert the source to a string. Set the StringFormat property to a .NET formatting string that you would use with the static String.Format format to display the object. When using this formatting string within a markup extension, surround it with single quotation marks so the curly braces won't be mistaken for an embedded markup extension.
The ShowViewValues sample demonstrates how to use StringFormat in XAML.
The WhatSizeBindings sample demonstrates displaying the size of the page with bindings to the Width and Height properties of the ContentPage.
Why is it called "Path"?
The Path property of Binding is so called because it can be a series of properties and indexers separated by periods. The BindingPathDemos sample shows several examples.
Binding value converters
When the source and target properties of a binding are different types, you can convert between the types using a binding converter. This is a class that implements the IValueConverter interface and contains two methods: Convert to convert the source to the target, and ConvertBack to convert the target to the source.
The IntToBoolConverter class in the Xamarin.FormsBook.Toolkit library is an example for converting an int to a bool. It is demonstrated by the ButtonEnabler sample, which only enables the Button if at least one character has been typed into an Entry.
The BoolToStringConverter class converts a bool to a string and defines two properties to specify what text should be returned for false and true values.
The BoolToColorConverter is similar. The SwitchText sample demonstrates using these two converters to display different texts in different colors based on a Switch setting.
The generic BoolToObjectConverter can replace the BoolToStringConverter and BoolToColorConverter and serve as a generalized bool-to-object converter of any type.
Bindings and custom views
You can simplify custom controls using data bindings. The NewCheckBox.cs code file defines Text, TextColor, FontSize, FontAttributes, and IsChecked properties, but has no logic at all for the visuals of the control.
Instead the NewCheckBox.cs.xaml file contains all the markup for the control's visuals through data bindings on the Label elements based on the properties defined in the code-behind file.
The NewCheckBoxDemo sample demonstrates the NewCheckBox custom control.
