Skip to end of metadata
Go to start of metadata

You are viewing an old version of this page. View the current version.

Compare with Current View Page History

« Previous Version 11 Next »

Unknown macro: {scrollbar}

Data Binding and Model-View-Controller Framework

As the XUL framework progressed, Pentaho developed a need for a clean, underlying model-view-controller (MVC) architecture application. MVC provides for a clean separation between application data (models), view logic (controllers) and the user interface (views). This separation creates loosely coupled components that are easier to maintain and test. For a more in-depth look at building Pentaho XUL applications with the MVC pattern, please refer to the excellent MVC in XUL applications article by Aaron Phillips: http://wiki.pentaho.com/display/PLATFORM/MVC+in+Pentaho+Xul+Applications

At the heart of any MVC application framework lies a method for synchronizing data between the models and views. Many frameworks leave this "housekeeping" to the developer. XUL bindings offer a more developer-friendly approach.

What's in a Binding?

A XUL binding object consists of four primary and two optional pieces of data:

  • Two XulEventSource objects – one "Source," the other "Target" – and a property for each to "Bind" together.
  • A binding strategy (one-way, bi-directional, or bind-once).

A converter object to manage data translation between the two is also an option.

Creating a Binding Object

There are several methods for creating a binding object in the XUL framework. Some are as simple as calling bind() with four strings from an event handler. All of those methods are covered in the aforementioned MVC document. Below is the most basic representation of a binding:

Binding bind = new Binding(sourceObject, "firstName", targetObject, "value");

When added to a binding context (explained later in this guide) it will synchronize data between sourceObject and targetObject by way of firstName and value respectively.

Because Java lacks first-class support for properties, and it's bad form to write objects with direct member access, a binding accesses data by way of the JavaBean standard. At the JavaBean level, the binding looks something like this:

sourceObject.getFirstName() => targetObject.setValue()
sourceObject.setFirstName() <= targetObject.getValue()

Binding Strategies

By default, a binding object represents a synchronization bi-directionally. Any change to the source will update the target and visa-versa. You can optionally prescribe for a one-way binding between source and target as such:

binding.setBindingType(Binding.Type.ONE_WAY);

Where ONE_WAY is a type defined in Binding.Type enumeration. A one-way binding will send data from the source to the target but not the other way around.

Future versions will introduce the concept of a "bind-once" strategy that will in essence "flash" a snapshot of data between objects at the time of the binding's instantiation.

Conversions

You can further extend the flexibility of your bindings by providing a BindingConvertor object to manage the translation of data between objects:

BindingConvertor.java

public abstract class BindingConvertor<V, R> {
    ...
    public abstract R sourceToTarget(V value);
    public abstract V targetToSource(R value);
}

Below is a simple implementation that binds the value of a XulTextbox with the selectedIndex of a XulMenuList. When a user enters a numeric string into the text box, it will be converted into an integer before being passed to the setSelectedIndex method of the menu list:

Binding binding = new Binding(textbox, "value", dropdown, "selectedIndex");

BindingConvertor conversion = new BindingConvertor<String, Integer>(){
    @Override
    public Integer sourceToTarget(String value) {
        return Integer.parseInt(value);
    }

    @Override
    public String targetToSource(Integer value) {
        return value.toString();
    }
}

binding.setConversion(conversion);

The Binding Context

Bindings in and of themselves don't actually do anything; they simply describe the relationship between objects. The actual establishment of a binding is performed by a BindingContext object. However, you never have to deal with a BindingContext directly because every XulDomContainer has one. To add a new binding object to the context, simply pass the binding to the addBinding() method of the XulDomContainer.

  • No labels