java.lang.Object
io.github.palexdev.materialfx.bindings.base.AbstractBindingHelper<T>
io.github.palexdev.materialfx.bindings.BiBindingHelper<T>
- Type Parameters:
T- the properties' value type
Binding helper for bidirectional bindings.
Bidirectional bindings are syntactical sugar, because basically it's a listener attached to one or more observable values
which acts as 'sources', when one of them change the target is updated and all the other sources are updated.
There is one issue though: when a source changes and the value is updated, there's a 'bounce' effect
because all the other sources are updated causing the updateTarget to trigger every time. The same unwanted effect
occurs when the target changes, as the sources update will then trigger again the updateTarget.
To avoid this, and improve performance, two boolean flags are used to stop the listeners from
proceeding with useless updates.
There's also another issue. In JavaFX when you bind the target multiple times
(so you have multiple sources) the properties will have the value of the last used source.
This helper though, stores the sources in a Map, which as you know it's not ordered. I could have used
a LinkedHashMap, but I wanted to use a WeakHashMap to avoid memory leaks (I hope). Writing a
WeakLinkedHashMap would have been too much work, and also very complicated, so in the end I created the
BindingsMap,
which allows to retrieve the sources in order of insertion.
The Map associates the source observable with the BiConsumer responsible for updating it.
-
Field Summary
FieldsFields inherited from class io.github.palexdev.materialfx.bindings.base.AbstractBindingHelper
sourceListener, target, targetUpdater -
Constructor Summary
Constructors -
Method Summary
Modifier and TypeMethodDescriptionaddSource(ObservableValue<? extends T> source, BiConsumer<T, T> updater) Adds the given source andBiConsumercto the sources map.addSources(BindingsMap<ObservableValue<? extends T>, BiConsumer<T, T>> sources) Adds all the given entries (as a Map) to this helper's sources map.protected voidEmpty by default.protected voidEmpty by default.bind(ObservableValue<? extends T> target) Sets the target to the specified one, and adds the targetListener to it.voidclear()Detaches the sourceListener from all the sources then clears the sources map.voiddispose()Callsclear()and in addition to that also the target is set to null (and the targetListener removed too).protected BindingsMap<ObservableValue<? extends T>,BiConsumer<T, T>> LinkedList<WeakReference<ObservableValue<? extends T>>>voidCauses the target to update with the last source's value.booleanChecks if the helper has been disposed before.booleanbooleanstatic <T> BiBindingHelper<T>newFor(BiBindingHelper<T> first, BiBindingHelper<T> second, boolean overrideTargetUpdater) Creates a newBiBindingHelperfrom the two given ones.intsize()voidunbind(ObservableValue<? extends T> source) Removes the given source from the sources map and also removes the sourceListener from it.protected voidupdateSource(ObservableValue<? extends T> source, BiConsumer<T, T> updater, T oldValue, T newValue) Updates the given source using the givenBiConsumerprotected voidupdateSources(T oldValue, T newValue) Invoked by the targetListener, it's responsible for updating the sources by callingupdateSource(ObservableValue, BiConsumer, Object, Object).protected voidupdateTarget(ObservableValue<? extends T> updatingSource, T oldValue, T newValue) Invoked by the sourceListener, it's responsible for updating the specified target using the specified targetUpdaterBiConsumer.with(BiConsumer<T, T> targetUpdater) Sets the targetUpdaterBiConsumer.Methods inherited from class io.github.palexdev.materialfx.bindings.base.AbstractBindingHelper
afterBind, afterUnbind, afterUpdateTarget, beforeBind, beforeUnbind, beforeUpdateTarget
-
Field Details
-
fromSource
protected boolean fromSource -
fromTarget
protected boolean fromTarget
-
-
Constructor Details
-
BiBindingHelper
public BiBindingHelper()
-
-
Method Details
-
bind
Sets the target to the specified one, and adds the targetListener to it.- Specified by:
bindin classAbstractBindingHelper<T>
-
with
Sets the targetUpdaterBiConsumer.- Specified by:
within classAbstractBindingHelper<T>
-
addSource
Adds the given source andBiConsumercto the sources map. Also callsAbstractBindingHelper.beforeBind()andAbstractBindingHelper.afterBind().- Parameters:
source- the source observableupdater- theBiConsumerresponsible for updating the source when the target changes
-
addSources
public BiBindingHelper<T> addSources(BindingsMap<ObservableValue<? extends T>, BiConsumer<T, T>> sources) Adds all the given entries (as a Map) to this helper's sources map. To ensure that the insertion order is maintained,BindingsMap.combine(BindingsMap)is used. Also callsAbstractBindingHelper.beforeBind()andAbstractBindingHelper.afterBind(). -
updateSources
Invoked by the targetListener, it's responsible for updating the sources by callingupdateSource(ObservableValue, BiConsumer, Object, Object). Also calls beforeUpdateSources() and afterUpdateSources() If the method is triggered byupdateTarget(ObservableValue, Object, Object), so the fromTarget flag is true, exits immediately. Sets the fromSource flag to true then updates the sources. The whole process is wrapped in a try-finally block as it's super important that the flag is reset at the end. -
updateSource
protected void updateSource(ObservableValue<? extends T> source, BiConsumer<T, T> updater, T oldValue, T newValue) Updates the given source using the givenBiConsumer -
updateTarget
Invoked by the sourceListener, it's responsible for updating the specified target using the specified targetUpdaterBiConsumer.Also calls
If the method is triggered byAbstractBindingHelper.beforeUpdateTarget()andAbstractBindingHelper.afterUpdateTarget().updateSources(Object, Object), so the fromSource flag is true, exits immediately. Sets the fromTarget flag to true then updates the target. Sets the fromSource flag to true as now it's needed to also update all the other sources (except for the updatingSource, the one that triggered the target update). Also calls beforeUpdateTarget() and afterUpdateTarget() The whole process is wrapped in a try-finally block as it's super important to reset both the flags at the end.- Overrides:
updateTargetin classAbstractBindingHelper<T>- Parameters:
updatingSource- the source that triggered the target updateoldValue- the source's oldValuenewValue- the source's newValue
-
invalidate
public void invalidate()Causes the target to update with the last source's value.The last source is retrieved using
This is necessary to 'simulate' the JavaFX's eager evaluation of bindings.BindingsMap.getLastKey().- Specified by:
invalidatein classAbstractBindingHelper<T>
-
unbind
Removes the given source from the sources map and also removes the sourceListener from it. Also callsAbstractBindingHelper.beforeUnbind(),AbstractBindingHelper.afterUnbind(). -
clear
public void clear()Detaches the sourceListener from all the sources then clears the sources map.This means that the helper won't be usable anymore until
addSource(ObservableValue, BiConsumer)oraddSources(BindingsMap)are called again. -
dispose
public void dispose()Callsclear()and in addition to that also the target is set to null (and the targetListener removed too).This means that the helper won't be usable anymore until
bind(ObservableValue)andaddSource(ObservableValue, BiConsumer)oraddSources(BindingsMap)are called again.- Specified by:
disposein classAbstractBindingHelper<T>
-
beforeUpdateSources
protected void beforeUpdateSources()Empty by default. -
afterUpdateSources
protected void afterUpdateSources()Empty by default. -
isFromTarget
public boolean isFromTarget()- Returns:
- whether the updated is triggered by the updateTarget
-
isFromSource
public boolean isFromSource()- Returns:
- whether the update is triggered by the updateSources
-
isDispose
public boolean isDispose()Checks if the helper has been disposed before.- Specified by:
isDisposein classAbstractBindingHelper<T>
-
size
public int size()- Returns:
- the number of sources in the map.
-
getSources
- Returns:
- the sources map
-
getUnmodifiableSources
- Returns:
- an unmodifiable view of the map's keys stored in a
LinkedList(to keep track of insertion order), and wrapped inWeakReferences.
-
newFor
public static <T> BiBindingHelper<T> newFor(BiBindingHelper<T> first, BiBindingHelper<T> second, boolean overrideTargetUpdater) Creates a newBiBindingHelperfrom the two given ones. Note that at the end of the process both the helpers are disposed.- Parameters:
first- the first helpersecond- the second helperoverrideTargetUpdater- a flag to specify if the targetUpdater of the second helper must be used instead
-