Skip to main content

Notice: this Wiki will be going read only early in 2024 and edits will no longer be possible. Please see: https://gitlab.eclipse.org/eclipsefdn/helpdesk/-/wikis/Wiki-shutdown-plan for the plan.

Jump to: navigation, search

Difference between revisions of "JFace Data Binding/Original Design"

(added info about bugzilla as the preferred feedback channel)
m (JFace Data Binding moved to JFace Data Binding Design)
(No difference)

Revision as of 00:06, 21 December 2005

Note: The JFace data binding framework is new in 3.2 and will likely change during the 3.2 development cycle. For comments, design feed back, and bug reports, please enter bugs against Platform/UI using [DataBinding] in the summary.

Data binding allows easy linking of UI elements and models so that users can edit or view the data in the model. Traditionally, this is what you need to do to link, say, a text widget to a String property of a model object:

  • Copy the current value of the model property to the text widget.
  • Register listeners with the widget and the model object to propagate changes

made on one side to the other side.

The same basic principle applies to binding a list widget's contents to a collection property of a model object.

Using the data binding framework relieves you from writing and registering listeners yourself, and provides a common infrastructure for validation and conversion. It makes it easy to connect data sources to widgets such as text fields, combos, tables and trees, for viewing and editing. In real life scenarios, changes on one side are not always propagated to the other side right away - changes need to be validated, values converted, and different update policies followed. The data binding framework covers these more advanced aspects as well.

<div id="simple_example"/>

Simple Example

Figure 1 depicts a simple binding of two visual elements. In this case the both the model and target objects are Text widgets. The binding of the two widget is done by calling a bind JFace-DataBinding-tag2.png on a binding context JFace-DataBinding-tag1.png. At runtime JFace-DataBinding-tag3.png, the model's value is first copied to the target. The binding framework will then listen for changes on the target and model values, and propagate changes as to keep both sides in step.

JFace-DataBinding-simplebind.png Figure 1

<div id="design_goals"/>

Design Goals

  • Easy to use
    • Make the default cases easy: For example, simple binding of a text widget should be one line of code.
    • Should not require new or custom controls, or wrappering of existing controls: Keep the concern of creating the widgets separate. Ideally, the code for creating the widgets stays exactly the same, and only the setting of initial values and the registering of listeners is replaced by calls to the data binding framework.
    • Enable lifecycle management: For example, disposing of a SWT composite should de-register all listeners and other helper objects used for binding controls in that composite.
  • Customizable
    • Keep binding code separate from code that creates the widgets: This lets users create widgets any way they want, including the use of a visual editor.
    • Support pluggable validators and converters (but provide defaults): For example, provide default converters (formatters) and validators for Integer and floating point numbers.
    • Allow to bind to different aspects of an object or a control: For example, binding to the enablement state of a control instead of its value, or in the case of the spinner widget, binding to the current selection, the min value, and the max value.
  • Easily Extensible
    • For supporting new or custom controls
    • For supporting other data sources

<div id="basic_idea"/>

Basic Idea

In terms of the data binding framework, binding involves two updatable objects whose state or current value is kept in sync (see Figure 2). The updatable objects are called target and model, respectively. An Updatable object normalize access to a value, and to notifications when that value has changed. Often, but not always, the target updatable will represent a UI widget, and the model updatable will represent a model object or a property of a model object. At binding time, the current state of the model is copied to the target. After that, updates to both the target updatable and the model updatable will be tracked and propagated to the other updatable. The binding activity is to listen for changes on the target and model updatables, and utilize a converter and a validator to propagate these changes across.

JFace-DataBinding-bindingdiagram.png Figure 2

For example, to bind a SWT text widget txtName to the "name" property of a model object mPerson, the framework creates an updatable value object (target) for txtName, and an updatable value object (model) for the "name" property of mPerson. In code, it looks like this:

   IUpdatable target = dataBindingContext.createUpdatable(txtName);
   IUpdatable model = dataBindingContext.createUpdatable(new PropertyDescription(mPerson, "name"));
   dataBindingContext.bind(target, model, null);

Updatable objects are created from description objects using factories. Description objects are interpreted by factories that create updatable objects, the data binding framework does not impose any semantics on them. Implementers of IUpdatableFactory specify for which description objects they can create updatable objects.

The data binding context offers methods for binding on the level of description objects directly, so that the above example boils down to just one line of code:

   dataBindingContext.bind(txtName, new PropertyDescription(mPerson, "name"), null);

The third argument of bind() is an optional bind spec object that can specify a custom validator or converter to be used.

Binding is always performed within a data binding context. The data binding context defines a common lifecycle (i.e. disposing) for the updatable objects created within it. Policy decisions can also be made for all bindings within a context, such as whether validation and updating should be performed automatically or not. Finally, you can register factories for creating updatable objects, validators, and converters with a data binding context. This is what makes the data binding framework extensible.

A binding can be created on the (lower) level of updatable objects directly, or on the (higher) level of description objects.

<div id="detailed_explanation"/>

Data Binding in Detail

This section explains the main aspects of the data binding framework in detail.

DataBinding

The class DataBinding contains a number of static methods for creating and setting up a data binding context. When creating a data binding context, it is important to provide it with factories for creating updatable objects. For the common case of creating a data binding context whose life cycle is bound to an SWT composite, and which supports binding to SWT controls, JFace viewers, and POJO model objects with JavaBeans-style notification, the following convenience method is provided:

	/**
	 * Creates a data binding context whose lifecycle is bound to an SWT
	 * control, and which supports binding to SWT controls, JFace viewers, and
	 * POJO model objects with JavaBeans-style notification.
	 */
	public static IDataBindingContext createContext(Control control);

IDataBindingContext

Binding is performed within a data binding context. The factories registered with a data binding context determine how it creates updatable objects from description objects, and which converters and validators are used when no specific converter or validator is given.

IUpdatableValue

An updatable value is an updatable object holding a single value. An updatable value can be bound to another updatable value. Binding a target and a model value first sets the current value of the target to be the current value of the model, and from then on, tracks changes in both the target and the model and whenever a change is performed on either side, this change will be performed on the other side.

When binding two updatable values of different types (as specified by their getValueType() return values), data types need to be converted. Clients can provide converters explicitly, or use default converters provided by the data binding context.

IUpdatableCollection

An updatable collection holds a collection of elements. It notifies its listeners about changes on a fine-grained level, i.e. additions and removals of elements, and changes within an element.

Converters and Validators

Sometimes, data needs to be validated. In the simplest case, not all String values can be parsed to an int, float, or Date, and thus any change to the string value needs to be validated before it can be converted. The result of the validation is an error message. To display this message in the UI, data binding can be used, since DatabindingService.getValidationMessage() returns an updatable value containing strings:

databindingService.bind(validationErrorTextWidget, “text”,
	databindingService.getValidationMessage());

Update and validation policies

On the level of the data binding context, updates can either happen whenever a change event is received (POLICY_AUTOMATIC), or upon calling an explicit method (POLICY_EXPLICIT).

The SWTUpdatableFactory supports different update policies: TIME_EARLY (on every key press), TIME_LATE (on focus lost), and TIME_NEVER (no change events are generated).

The SWTUpdatableFactory supports different update policies: TIME_EARLY (on every key press), TIME_LATE (on focus lost), and TIME_NEVER (no change events are generated).

Writing a factory for creating updatable objects

Status of the Implementation

See the scenarios document for an overview of the scenarios that are covered by the current implementation.

The following is a rough list of unfinished items:

  • More tests needed
  • Update policies are not implemented (currently hardwired to POLICY_AUTOMATIC)
  • For SWTUpdatableFactory, TIME_EARLY and TIME_LATE is only implemented for Text
  • Some default converters and validators missing

Copyright © Eclipse Foundation, Inc. All Rights Reserved.