[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [Newsgroup Home]
[news.eclipse.platform.rcp] Re: [DataBinding] Does there exist a BufferedObservable?

Daniel Krügler wrote:
After having written this description out of my head I tried to code
it down and found out that I gave some misleading descriptions :-(

Here a corrected form:

<snip>

I also went through the PresentationModel pdf at JGoodies.com which filled in the rest of the picture. I think I follow you now.

I agree that this is also some form of buffering strategy, but it is
local to one binding (which sometimes is an advantage, of-course) and
validation is also deferred according to my understanding of
POLICY_ON_REQUEST

You are correct, I should have said POLICY_CONVERT. The basic data binding pipeline is:


1. get source observable value
2. validate after get
3. convert to destination type
4. validate after convert
5. validate before set
6. set destination observable value

POLICY_ON_REQUEST does not execute this pipeline automatically, but waits until Binding.updateModel() is called. POLICY_CONVERT, by contrast, performs steps 1 through 4. POLICY_UPDATE performs all steps.

2. To hold off on updating the model until some cross-field validation constraint is satisfied (e.g. in a date range, the start date must be on or before the end date) you can use MultiValidator:

Thanks, this looks very cool! Nevertheless, I assume that I need at least some form of adaption to the jgoodies binding for easier adaption of the new binding.

I not sure what you mean here.

So one difference is that PresentationModel is more or less a map
from property to observable (not to the value, even though for convenience reasons they are also accessible). Let me give a sketch
in which way we use PresentationModel's and BufferedValueModel's in
our code:

Question: from what I saw in the JGoodies slideshow, it looks like the PresentationModel is intimately familiar with the model object. However using strings to distinguish property names is not going to be portable to, say, EMF. So I'm wonder However the way you describe it makes it look like a generic switchboard:


interface IPresentationModel {
  public IObservableValue getBufferedValue(IValueProperty)
  public IObservableList getBufferedList(IListProperty)
  public IObservableSet getBufferedSet(ISetProperty)
  public IObservableMap getBufferedMap(IMapProperty)
}

We wouldn't need to create IBufferedObservable* interfaces since we can use IObservable.isStale and IStaleListener to track whether each observable is "buffering" (i.e. out of sync with model)

2) We currently need to wrap this POJO in a Bean, that simply forwards
all properties of the POJO but sends proper Java Bean property change
events (I'm very impressed that JFace databinding allows direct usage
of POJO's!).

Quick note, the POJO observables only send change events if the change is initiated *through the IObservable's interface*, and only for that particular observable instance. So setting values directly on the POJO is discouraged since you don't get updates.


3) Before entering the UI layer, the beans are wrapped as presentation models:

PresentationModel pres = new PresentationModel(bean);

4) The UI layer gets the presentation model(s) and simply binds it's
observables "by name" to the corresponding widgets:

Text txt = new Text(parent, ...);
...
BufferedModel firstName = pres.getBufferedModel("firstName");

...
BindingFacade.bind(txt, firstName);

They are actually not aware of the direct nature of the complete
bean. They only need to now that there are some properties to
bind to widget's.

This sounds essentially like a two-stage binding. The presentation model would bind directly to the bean (or whatever type of model object) using POLICY_CONVERT update policies. In turn each UI form would bind its controls to the PM's observables.


5) Especially inside a local scope (dialog/wizard) it's nice to
simply say on Ok-pressed: pres.triggerCommit() and on any cancelling
step (either cancel-pressed or undo) triggerFlush() which unrolls
the current changes back to the original ones.

void triggerCommit() { bindingContext.updateModels(); } void triggerFlush() { bindingContext.updateTargets(); }

Finally let me add one further remark: In the jgoodies databinding
framework you don't always need to have an individual observable
just to observe changes of some characteristic property: E.g. I
can add or remove change listener's to the buffering state of
the IBufferedObservableValue without access to the actual observable,
because in this case I only need the change deltas in the property
observer and nowhere else.

We've tried to reduce the cost of creating observables by not registering listeners on the underlying object (e.g. bean) until you actually add listeners to the observable--not sure if that mitigates your concern but I thought I'd mention it.


I sometimes miss that fact in Jface
databinding, although it (usually) provides what I need: With further
wrapper techniques I could provide a *constant* view onto the
buffering state or the trigger channel (jface has ConstantObservable)
which do only exist such that clients can register IValueChangeListener's on them.

I don't follow you here.

It sounds like this is something we should take a closer look at. Would you submit a feature enhancement so we can discuss this further?

Matthew