Open NIKE3500 opened 6 years ago
Thanks for the thorough explanation. We need to make ignoreParentBuilder
component aware I think. Will look into it.
I also think this would be the best solution. However, I don't see how this should work when directly binding a collection (e.g. the children collection of a component)
Correct, we need another solution for this case.
I thought a bit about all this and came to the conclusion that the MutableList.bind()
method cannot be saved. In its current state it has a side effect that on the one hand might not be expected and on the other hand does not serve the purpose it was created for (as can be seen above). The side effect can also not be fixed as one cannot be sure in which context the method is called.
My suggestion would therefore be to remove or at least deprecate the method. If a "bind" method for normal lists is required it should be implemented without such global side effects. When using it with builders for binding a children collection it should simply cause the "duplicate" exception. Using builders to create and attach a component and then attaching it again is an issue that is debuggable and should be more or less easily visible for developers.
For binding children lists I would suggest an overload for bindChildren
In their documentation it should be clearly stated that these methods can be used with builders and should be used if builders are a requirement.
In the methods an attached property (ideally a counter) on "this" should keep track on whether builder should currently create objects. opcr
should check and respect that flag such that existing builders still work (at least the ones provided by the framework).
Having two methods here allows ditching the normal bind
method as for example for a BorderPane
the center.bind
call would simply become bindChildren(center, ...)
. I admit that this is not as elegantly written, but in my opinion the tradeoff is worth it.
I my current project I try to use bindChildren to fill a VBox with custom controls. These controls use builders in their constructor to set themselves up. Unfortunately it turns out this breaks
bindChildren
. There are two ways this can break:I did some debugging and the cause of this seems to be the handling of the
FX.ignoreParentBuilder
flag.MutableList<TargetType>.bind
sets this to avoid adding a control to its parent when calling a builder and thusopcr
inbindChildren
(or comparable). Doing so would cause an exception as the binding will try to add that control as well, which then leads to a duplicate. However, a call chain in the form ofbindChildren
->builder->constructor->builder causes the inner builder to consume theFX.ignoreParentBuilder
, which leads to two issues:I created a sample for you to verify this behavior. It can simply be used as the MainView of a TornadoFX application. In my opinion it should be possible to use builders in constructors and the FX.ignoreParentBuilder flag seems to fragile to properly work. Unfortunately I have to admit that currently I have no idea how to fix this properly...
Here is the sample code: