Source path
The source path in an expression like {fx:Observe source=myModel.userName} or its short form ${myModel.userName} may refer to any of the following elements on myModel:
- a plain field or method with the name
userName, returning aString - a Java Beans-style method with the name
getUserName, returning aString(optionally with theisprefix if the type isboolean) - a JavaFX Beans-style method with the name
userNameProperty, returning anObservableValue<String>(orPropertyin case of bidirectional bindings)
The source path is resolved by evaluating it against the evaluation context. Alternatively, it can also be a statically reachable path, beginning with the name of a class.
For example, the following binding expression refers to the static
String.format(String, Object...)method, while themyModel.userNameargument is resolved against the evaluation context:<Label text="${String.format('Hello %s!', myModel.userName)}"/>
Member selection operator .
The member selection operator selects a member of a type:
<Label text="${user.address.streetName}"/>
It is null-tolerant and short-circuiting, which means that if one of the members is null, the rest of the expression evaluates to the default value of its last member. For example, if the last member in the expression ${user.address.postalCode} is of type int, the expression evaluates to zero if user or address is null.
If the path contains ObservableValue members, the expression is automatically re-evaluated when any of the observable values are changed. Expressions can also be re-evaluated when they depend on the content of observable collections such as ObservableList, ObservableSet, or ObservableMap. This does not apply to fx:Evaluate, which resolves its path once and does not observe it afterward.
The member selection operator looks just like the dot operator in Java, but its semantics are slightly different. In particular, the member selection operator “hides” the difference between a member of type Address and a member of type ObservableValue<Address>. In both cases, a value of type Address is selected, but the second case allows the expression to be automatically re-evaluated when the value is changed.
Observable selection operator ::
In some cases, it can be necessary to select the ObservableValue instance itself, and not the value contained within. Consider the following binding expression:
<MyAddressControl count="${user.addresses.size}"/>
In this example, addresses is a ListProperty<Address>. Since ListProperty<Address> implements ObservableValue<ObservableList<Address>>, the expression user.addresses selects the contained ObservableList<Address>. Consequently, .size selects the ObservableList.size() method, returning an int. Since the expression depends on the content of an observable collection, it is automatically re-evaluated when addresses are added or removed from the list.
The observable selection operator becomes necessary when the expression needs to access the ListProperty<Address> instance itself, instead of the contained ObservableList<Address>. For example:
<Label text="${user::addresses.name}"/>
In this case, .name selects the ReadOnlyProperty.getName() method on the ListProperty<Address> instance. The expression ${user.addresses.name} would not work the same way, because user.addresses selects the contained ObservableList<Address>, whose API is different from the API of ListProperty<Address>.
This distinction is useful whenever the observable object exposes members that are different from the members of its current value, or when you need to pass the observable instance to another expression instead of its contained value.
Unlike the member selection operator, the observable selection operator can also be placed in front of the first path segment. For example, ${::addresses.size} is a valid expression if addresses is an ObservableValue.
Content selection operator ..
When the path is prefixed with the content selection operator .., the expression does not operate on a single scalar value or property. Instead, it operates on the content of the collection identified by the source path.
Content selection is available for all expression types:
| Intrinsic | Normal form | Content selection form |
|---|---|---|
fx:Evaluate | $source | $..source |
fx:Observe | ${source} | ${..source} |
fx:Push | >{source} | >{..source} |
fx:Synchronize | #{source} | #{..source} |
Content selection semantics
-
fx:Evaluateresolves the source collection once, and adds its content to the target collection:<!-- corresponds to itemsProperty().addAll(source) --> <ListView items="$..source"/> -
fx:Observeestablishes a content binding between the target and source collections:<!-- corresponds to Bindings.bindContent(items, source) --> <ListView items="${..source}"/> -
fx:Pushestablishes a reverse content binding between the source and target collections:<!-- corresponds to Bindings.bindContent(source, items) --> <ListView items=">{..source}"/> -
fx:Synchronizeestablishes a bidirectional content binding between the target and source collections:<!-- corresponds to Bindings.bindContentBidirectional(items, source) --> <ListView items="#{..source}"/>
Attached properties
An attached property can be selected by wrapping the qualified attached property name in parentheses. The qualified attached property name consists of the name of the declaring class and the name of the property:
<VBox>
<Label VBox.margin="10" fx:id="myLabel"/>
<!-- Selects VBox.getMargin(myLabel) -->
<Label VBox.margin="$myLabel.(VBox.margin)"/>
</VBox>
Generic type witness
When a generic method is selected, it can sometimes be necessary to specify a type witness in order to preserve type information. A generic type witness is specified in angle brackets after the method name:
<MyControl value="${path.to.genericGetter<String>.value}"/>
In XML files, the < character can only be used as a markup delimiter, and must be escaped using < in attribute text. However, the FXML compiler accepts the non-standard literal form for better code readability.