Architecture
Cross-Sectional Data Binding
Although the state of the UI can be mostly defined by information from PMOs and the domain model, it sometimes must be additionaly influenced by other factors, such as system state, for instance. These factors are dealt with via cross-sectional data binding.
A good example for such aspects is the "browse mode". Many applications distinguish between:
-
"Edit Mode", in which data can be entered and modified on the UI
-
"Browse Mode", in which data in forms is shown, but can’t be modified
Often, applications toggle between these modes, for instance when "Editing" is started and completed. In browse mode all form fields should be read-only. This global editing state of the application thus influences many fields at once. Additionally, the browse mode overrides settings from PMOs. Even when a field is marked as editable by the PMO, it is write protected during browse mode.
linkki provides two technical means to implement cross-sectional data binding: PropertyDispatcher and PropertyBehaviors.
PropertyDispatcher
The BindingContext (see BindingContext Basics - BindingManager) uses a PropertyDispatcherFactory, which creates multiple linked PropertyDispatchers. These dispatchers in turn are used to bind PMO properties (see Binding of further UI element properties). PropertyDispatchers have methods to determine the data type and value of a property. By default linkki creates four linked dispatchers, where each delegates to the next if it can’t provide the value:
-
BehaviorDependentDispatcherusesPropertyBehaviors(see next section, PropertyBehaviors) -
BindingAnnotationDispatcherprovides information that can be read directly from UI annotations -
ReflectionPropertyDispatcheruses reflection to access methods on PMO or domain model derived from property names -
ExceptionPropertyDispatcherthrows an exception if the required property is not found. This often indicates a spelling error in the method name, which causes theReflectionPropertyDispatcherto be unable to find the proper method
Custom dispatchers can be created via a PropertyDispatcherFactory (in its own BindingContext). There the method createCustomDispatchers must be overwritten to create one or more custom dispatchers. These dispatchers are inserted between BehaviorDependentDispatcher and BindingAnnotationDispatcher.
PropertyBehaviors
PropertyBehaviors are created by a PropertyBehaviorProvider that can be passed to a BindingContext as constructor parameter. In this way, the application can configure which PropertyBehaviors should be used in the BindingContext.
A BehaviorDependentDispatcher can control the behavior of properties through PropertyBehaviors. Only a selection of properties can be controlled with it: Visibility (isVisible), editability (isWritable) and visibility of errors (isShowValidationMessages). For this, all PropertyBehaviors are called; if all return true, the BehaviorDependentDispatcher sends the request to the next PropertyDispatcher, otherwise it returns false or an empty error list, or doesn’t set the value.
For custom behaviors the interface PropertyBehavior can be implemented. That way, an entire page can be set into the editing or read-only mode:
class ReadOnlyBehavior implements PropertyBehavior {
private boolean editable;
public ReadOnlyBehavior(boolean editable) {
this.editable = editable;
}
@Override
public boolean isWritable(Object boundObject, String property) {
return editable;
}
}
