Data Binding
Data binding in AlterNET UI provides a simple and consistent way for apps to present and interact with data. Elements can be bound to data from different kinds of data sources in the form of .NET objects.
The data binding in AlterNET UI has several advantages over traditional models, including inherent support for data binding by a broad range of properties and clean separation of business logic from UI.
This article first discusses concepts fundamental to AlterNET UI data binding and then covers the usage of the Binding class and other features of data binding.
What is data binding?
Data binding is the process that establishes a connection between the app UI and
the data it displays. If the binding has the correct settings and the data
provides the proper notifications, when the data changes its value, the elements
that are bound to the data reflect changes automatically. Data binding can also
mean that if an outer representation of the data in an element changes, then the
underlying data can be automatically updated to reflect the change. For example,
if the user edits the value in a TextBox
element, the underlying data value is
automatically updated to reflect that change.
A typical use of data binding is to place server or local configuration data into forms or other UI controls. In AlterNET UI, this concept is expanded to include binding a broad range of properties to different kinds of data sources.
Basic data binding concepts
Data binding is essentially the bridge between your binding target and your binding source.
Typically, each binding has four components:
- A binding target object.
- A target property.
- A binding source.
- A path to the value in the binding source to use.
For example, if you bound the content of a
TextBox
to theEmployee.Name
property, you would set up your binding like the following table:Setting Value Target TextBox Target property Text Source object Employee
Source object value path Name
The target property must be a dependency property.
Most UIElement properties are dependency properties, and most dependency properties, except read-only ones, support data binding by default. Only types derived from DependencyObject can define dependency properties. All UIElement types derive from
DependencyObject
.
It's important to remember that when you're establishing a binding, you're
binding a binding target to a binding source. For example, if you're
displaying some data in a ListBox
using data binding, you're binding your ListBox
to the data.
To establish a binding, you use the Binding object.
The rest of this article discusses many of the concepts associated with and some
of the properties and usage of the Binding
object.
Data context
When data binding is declared on UIXML elements, they resolve data binding by
looking at their immediate DataContext
property. The data context is typically the binding source object for the
binding source value path evaluation. You can override this behavior in the
binding and set a specific binding source object value. If the DataContext
property for the object hosting the binding is not set, the parent element's
DataContext
property is checked, and so on, up until the root of the UIXML
object tree. In short, the data context used to resolve binding is inherited
from the parent unless explicitly set on the object.
Bindings can be configured to resolve with a specific object, as opposed to using the data context for binding resolution. Specifying a source object is used when, for example, you bind the foreground color of an object to the background color of another object. Data context isn't needed since the binding is resolved between those two objects. Inversely, bindings that aren't bound to specific source objects use data-context resolution.
When the DataContext
property changes, all bindings that could be affected by
the data context are reevaluated.
Direction of the data flow
The data flow of a binding can
go from the binding target to the binding source (for example, the source value
changes when a user edits the value of a TextBox
) and/or from the binding
source to the binding target (for example, your TextBox
content is updated
with changes in the binding source) if the binding source provides the proper
notifications.
You may want your app to enable users to change the data and propagate it back to the source object. Or you may not want to enable users to update the source data. You can control the flow of data by setting the Binding.Mode.
OneWay binding causes changes to the source property to automatically update the target property, but changes to the target property are not propagated back to the source property. This type of binding is appropriate if the control being bound is implicitly read-only. For instance, you may bind to a source such as a stock ticker, or perhaps your target property has no control interface provided for making changes, such as a data-bound background color of a table. If there's no need to monitor the changes of the target property, using the OneWay binding mode avoids the overhead of the TwoWay binding mode.
TwoWay binding causes changes to either the source property or the target property to automatically update the other. This type of binding is appropriate for editable forms or other fully interactive UI scenarios. Most properties default to OneWay binding, but some dependency properties (typically properties of user-editable controls such as the TextBox.Text and CheckBox.IsChecked default to TwoWay binding. A programmatic way to determine whether a dependency property binds one-way or two-way by default is to get the property metadata with DependencyProperty.GetMetadata and then check the Boolean value of the FrameworkPropertyMetadata.BindsTwoWayByDefault property.
OneWayToSource is the reverse of OneWay binding; it updates the source property when the target property changes. One example scenario is if you only need to reevaluate the source value from the UI.
OneTime binding causes the source property to initialize the target property but doesn't propagate subsequent changes. If the data context changes or the object in the data context changes, the change is not reflected in the target property. This type of binding is appropriate if either a snapshot of the current state is appropriate or the data is truly static. This type of binding is also useful if you want to initialize your target property with some value from a source property and the data context isn't known in advance. This mode is essentially a simpler form of OneWay binding that provides better performance in cases where the source value doesn't change.
To detect source changes (applicable to OneWay and TwoWay bindings), the source must implement a suitable property change notification mechanism, such as INotifyPropertyChanged.
What triggers source updates
Bindings that are TwoWay or OneWayToSource listen for changes in the target property and propagate them back to the source, known as updating the source. For example, you may edit the text of a TextBox to change the underlying source value.
However, is your source value updated while editing the text or after you finish editing the text and the control loses focus? The Binding.UpdateSourceTrigger property determines what triggers the update of the source.
If the UpdateSourceTrigger
value is
UpdateSourceTrigger.PropertyChanged,
then the value pointed to by the right arrow of
TwoWay or the
OneWayToSource bindings is updated as
soon as the target property changes. However, if the UpdateSourceTrigger
value
is LostFocus, then that value
only is updated with the new value when the target property loses focus.
Similar to the Mode property, different
dependency properties have different default
UpdateSourceTrigger values. The default
value for most dependency properties is
PropertyChanged, which causes the
source property's value to instantly change when the target property value is
changed. Instant changes are fine for CheckBox
and other simple controls. However, for text fields, updating after every
keystroke can diminish performance and denies the user the usual opportunity to
backspace and fix typing errors before committing to the new value. For example,
the TextBox.Text
property defaults to the UpdateSourceTrigger
value of
LostFocus, which causes the
source value to change only when the control element loses focus, not when the
TextBox.Text
property is changed. See the
UpdateSourceTrigger property page for
information about how to find the default value of a dependency property.
The following table provides an example scenario for each UpdateSourceTrigger value using the TextBox as an example.
UpdateSourceTrigger value | When the source value is updated | Example scenario for TextBox |
---|---|---|
LostFocus (default for TextBox.Text) |
When the TextBox control loses focus. | A TextBox that is associated with validation logic. |
PropertyChanged |
As you type into the TextBox. | TextBox controls in a chat room window. |
Explicit |
When the app calls UpdateSource. | TextBox controls in an editable form (updates the source values only when the user presses the submit button). |