Product manager of MeeGo native tools.
lavonius | 11 November, 2011 15:35
[Guestwritten by Michael Hasselmann.]
A property binding exists between two properties 'a' and 'b', written as 'a: b' such that the value of 'a' updates whenever 'b' updates. Typical use-cases are: controlling element size, controlling position of an element through anchors, dynamically changing text or images, controlling element colors or controlling button states.
In its simplest form, 'a' – once bound to 'b' – maintains the same value as 'b', for the lifetime of the property binding. In its more advanced form, 'a' is bound to an arbitrary JavaScript expression that makes use of 'b', like so: 'a: b + 1'.
It is also possible to bind 'a' to more than one property: 'a: b * c + 1'. Here, the expression will be evaluated whenever 'b' or 'c' changes.
The following table shows the value of 'a', depending on how 'b' and 'c' change their values over time.
a:b*c+1 a b c
initial state 1 0 0
b = 1 1 1 0
c = 2 3 1 2
b = -3 -5 -3 2
The possibilities for property bindings seem unlimited, and indeed, they can also be established between properties of different type. Consider a color property 'c' being bound to an enumeration type 'e'. The naive approach, 'c: e', will not work. But 'e' can be handed to a conversion function, done with some JavaScript:
function toColor(e) { switch(e) { case highlighted: return "blue"; case inactive: return "white"; default: return "black"; } }
Now the property binding can be written as:
c: toColor(e)
and it will work as expected. 'c' will update correctly even if toColor internally depends on another property but e, but such hidden dependencies are best avoided.
Never assign to bound properties. Properties are either free or bound (to other properties). Assigning a value explicitly is OK, as long as the property is free. Once it becomes bound, any new assignment would remove the previous property binding. This can be a source of bugs and as such, should be avoided.
Use property bindings over explicit state handling. Whenever state handling logic is used in QML, there is a more robust solution that relies on property binding instead and will achieve the same result. Hide the state handling behind new properties. Once the state handling logic grows, property bindings tend to scale better in terms of complexity.
Marking an item as active, through explicit state handling.
import QtQuick 1.0 // Becomes active once clicked, deactivates with next click. Rectangle { id: canvas anchors.fill: parent color: "green" MouseArea { anchors.fill: parent onClicked: { canvas.state == "activated" ? canvas.state = "" : canvas.state = "activated" } } states: [ State { name: "activated" PropertyChanges { target: canvas color: "red" } } ] }
Marking an item as active, through a new custom property bound to item's color property.
import QtQuick 1.0 // Becomes active once clicked, deactivates with next click. Rectangle { id: canvas anchors.fill: parent property bool activated: false color: activated ? "red" : "green" MouseArea { anchors.fill: parent onClicked: { canvas.activated = !canvas.activated } } }
The flexibility and ease of use explains why property bindings are used pervasively in programming with QML language. Elements should be designed as being purely dependent on their properties whenever it comes to dynamic changes. Combined with property bindings, these elements will work in a "fire-and-forget" fashion, meaning that after the initial setup, they will just keep working correctly, regardless of other considerations. This makes it possible to deal with more complex UI's but just as importantly, it also keeps the code clean and reduces the risk of introducing bugs.
Property bindings don't come for free though and under certain conditions the performance impact can become noticeable. This, however, will be material for a future article in this series.
Commentstruf | 12/11/2011, 17:51
I suppose there is a mistake in the table. Istead of -5 -3 -2 should be -5 -3 2
lavonius | 14/11/2011, 09:05
thank you for the pointer.
ilkkal | 18/11/2011, 10:43
Do you find that bindings should win over state handling even when the properties of a large number of elements depend on some property change? Say there is a property that has major effects on layout, label texts etc. Would you rather sprinkle the code with conditionals, or have all the changes grouped as PropertyChanges in a State?
mikhas4711 | 18/11/2011, 18:34
@ilkkal, I would still consider property bindings more robust, even in that case.
If the conditionals for the property bindings become too complex, then the introduction of new custom properties can help to simplify (though any new property means new state, so there's a natural trade-off).
Picking up your example where "one property has major effects on layout, label texts etc": This sounds as if you were using a dedicated Style component, and that's one of the places where I really like to use property bindings.
Then, whenever the Style component changes, I don't have to worry that some dependent property will be forgotten in the update.
If we consider transition animations (or properties that are explicitly used for transition animations), then that's *usually* not part of your core application logic, but rather pretty isolated UI effects.That is, your application should still work even if you removed the transition animations.
For those, it can make more sense to use explicit state handling instead.
ilkkal | 18/11/2011, 20:34
Michael, generally I do agree with you, not least because explicit states tend to result in more lines of code. I came across the specific situation I described recently in some code that suffered a bit from ad-hoc requirements specification, and I think with a little refactoring the whole problem would've gone away. It's just strange that explicit states are so redundant: they're not too useful as data, and neither are they very handy as API.
pjturpeau | 19/11/2011, 16:56
What is cool with states is when you need animations that are different from one transition to another.
Also, if more than one properties are need conditionals, it could be a bit cumbersome to maintain/update the code while prototyping your whole component logic...
I've no preference on one from another. However, from a performance point of view, a more detailed comparison might be interesting.
security testing
NokiaSecuirty | 11/11/2011, 17:27
testing