-
The Call of ChrismathuluR.J. LorimerFri, Nov 7 2008 @ 2:38 pm
-
Getting True Java Classes in JRubyR.J. LorimerThu, Sep 25 2008 @ 6:41 pm
-
JRuby 1.1.4 ReleasedR.J. LorimerFri, Aug 29 2008 @ 5:41 am
-
My XBoxR.J. LorimerMon, Aug 25 2008 @ 3:22 am
-
Why So Serious?R.J. LorimerSat, Aug 23 2008 @ 5:25 am
JFace Data Binding: Buffering Binding Updates
Bind Me Later
One of the key elements of any non-trivial data binding implementation is how you control the timing of the binding of data. Most of the simple examples of JFace or JGoodies data binding simply have ‘live’ bindings, where any change made on one side is immediately propagated to the other side. While this is valuable, and is certainly a neat party trick when you have two UI controls bound to the same field, it is in my estimation, the less common scenario.
In a majority of cases, you have a set of data; perhaps a large form in your UI, that is filled out by the user and changed as they see fit, and only when they are complete and ‘accept’ the changes are the changes actually bound back to the underlying model (at which time the model may also be saved to some data store).
This has the dual benefit of not only providing a working copy (the UI itself), but also of preventing a large amount of unnecessary messages being sent back and forth between the model and the UI.
JGoodies Comparison
In JGoodies, this type of delayed binding was handled by the BufferedValueModel, along with something that was referred to as a trigger channel, which was really just another binding in JGoodies that, when changed, cause the value model to ‘flush’ its buffer.
UpdateValueStrategy
JFace, on the other hand, has the concept of an UpdateValueStrategy that can be applied when creating any binding. This class contains several of the components of the binding, including the validation routine, the conversion routine, as well as the actual strategy for performing the update.
One of the mandatory arguments when you create an UpdateValueStrategy is an integer representing the update ‘policy’. There are four possible policies:
- POLICY_UPDATE - This means update as soon as the change occurs on the ‘source’ side.
- POLICYONREQUEST - This means, you guessed it, update on request. The question to be answered (which I promise I will, shortly) is how you request it.
- POLICY_CONVERT - This is just like
POLICY_ON_REQUESTbut also automatically runs the new value through the validation and conversion routines, so you can immediately provide user feedback as they type. It still requires you manually request the final binding however. This is the most likely candidate in real world use. - POLICY_NEVER - This allows you to create a uni-directional binding, where one side will never update the other.
In my previous blog entry, I simply used the UpdateValueStrategy.POLICY_UPDATE policy.
When you want to trigger an update, you need to tell all of the appropriate bindings to update from one direction to another. This is typically done through the DataBindingContext which is created as part of the binding process for a particular view.
A (Relatively) Simple Example
Here is a simple example, using the classes from my previous entry.
Text t = new Text(parent, SWT.BORDER); // At this time, the data binding context will capture this binding // and can refer back to it at a later time. ctx.bindValue( SWTObservables.observeText(t, SWT.Modify), BeanObservables.observeValue(someEmail, “subject”), toModel, fromModel );
Now, all we need to do, is create buttons to actually push the changes to the model at user request. As a bonus, we can also use this technique to perform a cancel or reset:
Button cancel = new Button(parent, SWT.PUSH); cancel.setText(“Cancel”); cancel.addListener(SWT.Selection, new Listener() { public void handleEvent(Event evt) { // Tell the context to re-set all of the targets to the model values. ctx.updateTargets(); } });
