Attribute definitions
Attribute definition helpers
defineBindableWithEvent (Xamarin.Forms)
Values and event handlers are very similar. They are both values: one has a concrete value, the other has a function value. That’s why in v2, values and events are both treated as individual scalar attributes.
That works most of the time, but some properties and events have a strong dependency. E.g.:
Entry: Text / TextChanged
Slider: Value / ValueChanged
ListView: SelectedIndex / SelectedIndex
This is required to be able to react to user interactions like users are inputting text, toggling a switch, etc. But in Xamarin.Forms, those events are also triggered by programmatic changes.
If you, as a developer, decides to toggle the switch from false to true, it will raise a Toggled
event - the same event if the users had toggle the switch themselves.
Firstly this makes it hard to differentiate if we are reacting to a user change or a programmatic change. The latter is not really interesting since we already know what’s inside the app model.
This behavior seems rather harmless because in case of programmatic change, Fabulous will see that the event is actually trying to set the related property to the same value, so no change is needed. Eg.: [Programmatic Change: Value = true] -> [Event msg: Value changed to true] -> [Value was true, now is true] -> [do nothing]
But on Android, this can lead to an infinite update loop. Android delays its event triggering a little bit so if the user is quickly changing the input, Fabulous and Android can get out of sync and freeze the app.
Example: User wants to write “Hello”
User taps letter
H
User taps letter
e
Android raises event “TextChanged: H” -> Fabulous will change the Entry’s text to
H
(wasHe
) -> triggering another eventAndroid raises event “TextChanged: He” -> Fabulous will change the Entry’s text to
He
(wasH
)Android raises event “TextChanged: H” (because of (3)) -> Fabulous will change to
H
(wasHe
)Android raises event “TextChanged: He” (because of (4)) -> Fabulous will change the Entry’s text to
He
(wasH
)etc.
To avoid this from happening, the only way is to ignore the events triggered by programmatic changes. This is done by removing the event handler before updating the value and reset it after.
To guarantee the order of execution, we need to handle both the property and the related event in a single attribute, where the UpdateNode
function of the attribute will take care of updating in the right order.
Remove old handler if any
Update the value (it will trigger an event, but we don’t listen to it anymore)
If attribute was removed, then we clean the old value
Otherwise we set the new value
Set the new handler if any
Here is the attribute declaration to use:
Before we had 2 attribute definitions (property and event)
Now, there is a new attribute definition to update both the property and the event in a single attribute.
Last updated