Property Binding

This application demonstrates Pivot's support for "property binding". This feature allows a caller to declaratively create a relationship between a source and target property such that changes to the source are automatically reflected in the target.

Property binding is most commonly used to establish a one-way relationship between a source and target value; however, as shown in the example, bi-directional bindings are also supported. Property relationships are established in markup using the following binding syntax:

targetProperty="${mappingFunction:sourceProperty}"

"mappingFunction" is an optional script function that can be used to transform a bound source value before it is applied to the target property. If omitted, the source value is simply applied to the target as-is.

The BXML source for the example is shown below:

            
            <databinding:PropertyBinding title="Property Binding" maximized="true"
                xmlns:bxml="http://pivot.apache.org/bxml"
                xmlns:databinding="org.apache.pivot.tutorials.databinding"
                xmlns="org.apache.pivot.wtk">
                <bxml:script>
                importClass(org.apache.pivot.tutorials.databinding.PropertyBinding);

                function toUpperCase(value) {
                    return value.toUpperCase();
                }

                function toHex(color) {
                    return PropertyBinding.toHex(color);
                }
                </bxml:script>

                <Border>
                    <Form>
                        <Form.Section heading="One-Way Binding">
                            <TextInput bxml:id="textInput" Form.label="Text Input"/>
                            <Label Form.label="Text" text="${textInput.text}"/>
                            <Label Form.label="Uppercase Text" text="${toUpperCase:textInput.text}"/>
                        </Form.Section>

                        <Form.Section heading="Two-Way Binding">
                            <TextInput bxml:id="textInput1" Form.label="Text Input 1" text="${textInput2.text}"/>
                            <TextInput bxml:id="textInput2" Form.label="Text Input 2" text="${textInput1.text}"/>
                        </Form.Section>

                        <Form.Section heading="Style Binding">
                            <ColorChooserButton bxml:id="colorChooserButton" Form.label="Color Chooser Button"
                                selectedColor="#000000"/>
                            <Label Form.label="Selected Color" text="${colorChooserButton.selectedColor}">
                                <styles color="${colorChooserButton.selectedColor}"/>
                            </Label>
                            <Label Form.label="Selected Color (Hex)" text="${toHex:colorChooserButton.selectedColor}">
                                <styles color="${toHex:colorChooserButton.selectedColor}"/>
                            </Label>
                        </Form.Section>

                        <Form.Section heading="Manual Binding">
                            <ListButton bxml:id="listButton" Form.label="List Button"
                                listData="['Zero', 'One', 'Two', 'Three']" selectedIndex="0"/>
                            <Label bxml:id="listButtonLabel1" Form.label="Selected Item"/>
                            <Label bxml:id="listButtonLabel2" Form.label="Uppercase Selected Item"/>
                        </Form.Section>
                    </Form>
                </Border>
            </databinding:PropertyBinding>
            
        

Note the use of mapping functions to transform the "textInput.text" property to all caps before applying it to the bound label. Similarly, a mapping function is used to transform the "selectedColor" property of the ColorChooserButton to a hex string so it can be used as the value for the "color" style of the selected color label.

Bindings are not limited to BXML - they can also be defined programmatically. For example, the "manual binding" shown in the demo is constructed in Java code as shown in the initialize() method below:

            
            package org.apache.pivot.tutorials.databinding;

            import java.awt.Color;
            import java.net.URL;

            import org.apache.pivot.beans.Bindable;
            import org.apache.pivot.beans.NamespaceBinding;
            import org.apache.pivot.collections.Map;
            import org.apache.pivot.util.Resources;
            import org.apache.pivot.wtk.Window;

            public class PropertyBinding extends Window implements Bindable {
                @Override
                public void initialize(Map<String, Object> namespace, URL location, Resources resources) {
                    // Bind list button selection to label text
                    NamespaceBinding namespaceBinding1 = new NamespaceBinding(namespace,
                        "listButton.selectedItem", "listButtonLabel1.text");

                    namespaceBinding1.bind();

                    // Bind list button selection to label text with bind mapping
                    NamespaceBinding namespaceBinding2 = new NamespaceBinding(namespace,
                        "listButton.selectedItem", "listButtonLabel2.text", new NamespaceBinding.BindMapping() {
                        @Override
                        public Object evaluate(Object value) {
                            return value.toString().toUpperCase();
                        }
                    });

                    namespaceBinding2.bind();
                }

                public static String toHex(Color color) {
                    return String.format("#%02X%02X%02X", color.getRed(), color.getBlue(), color.getGreen());
                }
            }
            
        

The primary advantage to creating a binding relationship in code is that it can be "unbound" when it is no longer needed; once established, bindings defined in BXML cannot be removed.

Next: Localization