(Re-)Binding SWT forms with WindowBuilder
A very common case in UI applications are forms which are bound to exchangeable model objects. For example, one might want to bind this address form in such a way that you can set a new
Address
object at any time with the UI reflecting that change:The plain old binding can be created easily using WindowBuilder:
The resulting code might look like this:
public class AddressViewPart extends ViewPart { private DataBindingContext bindingContext; private Address address; private Text textName; @Override public void createPartControl(Composite parent) { parent.setLayout(new GridLayout(3, false)); Label lblName = new Label(parent, SWT.NONE); lblName.setText(Messages.YetAnotherViewPart_lblName_text); textName = new Text(parent, SWT.BORDER); textName.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, false, false, 2, 1)); // ... bindingContext = initDataBindings(); } protected DataBindingContext initDataBindings() { DataBindingContext bindingContext = new DataBindingContext(); // IObservableValue textNameValue = WidgetProperties.text(SWT.Modify).observe(textName); IObservableValue addressNameValue = PojoProperties.value("name").observe(address); bindingContext.bindValue(textNameValue, addressNameValue, null, null); // return bindingContext; } }The tricky part is to bind this in such a way that the model object can be exchanged at any time. There are three possible ways:
1) Dispose bindings
The easiest way is to dispose all bindings and just re-bind whenever a new model object appears:
public class AddressViewPart extends ViewPart { // ... protected void setAddress(Address address) { this.address = address; if (bindingContext != null) bindingContext.dispose(); bindingContext = initDataBindings(); } // ... }Unfortunately, WindowBuilder insists on putting the
initDataBindings
call increatePartControl
. Also, if you are usingControlDecorationSupport
you will stumble upon Bug 341713 - DataBinding ControlDecorationSupport not disposed when DataBindingContext is disposed.2) Binding to a WritableValue
Another way is to use a detail binding to a
WritableValue
which can be changed at any time:public class AddressViewPart extends ViewPart { private WritableValue addressValue = new WritableValue(); protected void setAddress(Address address) { this.addressValue.setValue(address); } protected DataBindingContext initDataBindings() { // ... IObservableValue addressNameValue = PojoProperties.value("name").observeDetail(addressValue); // ... } }Such a Binding can be created in WindowBuilder:
3) Bean binding
Yet another way is to make the ViewPart itself a
Bean
withPropertyChangeSupport
:public class AddressViewPart extends ViewPart { private PropertyChangeSupport changes = new PropertyChangeSupport(this); private Address address; public Address getAddress() { return address; } public void setAddress(Address address) { changes.firePropertyChange("address", this.address, this.address = address); } public void addPropertyChangeListener(PropertyChangeListener l) { changes.addPropertyChangeListener(l); } public void removePropertyChangeListener(PropertyChangeListener l) { changes.removePropertyChangeListener(l); } protected DataBindingContext initDataBindings() { //... IObservableValue addressNameValue = BeanProperties.value("address.name").observe(this); //... } }While I like this way conceptionally, in practice it has the problems of Java’s PropertyChangeSupport being cumbersome. Also, JFace Data Binding doesn’t allow to mix Beans and Pojos, so if the Address object in the example is a Pojo, one will get
NoSuchMethodException: Address.addPropertyChangeListener(java.beans.PropertyChangeListener)
. And there seems to be no way to generate such a binding in WindowBuilder.
(Re-)Binding SWT forms with WindowBuilder
Posted by
neizlog
on Monday, April 11, 2011
/
via ralfebert.de
0 comments:
Post a Comment