I defined an FXML file that contains an fx:reference element using a source attribute containing the keyword controller
. Like this <fx:reference source="controller.viewModel"/>
. So the fx:reference references the controller of the FXML file.
And the good thing, this syntax works.
I found a few examples that are using the keyword controller
in expression bindings, like this <Label text="${controller.text}"/>
But I found no documentation about this keyword controller
.
I checked the documentation at http://docs.oracle.com/javase/8/javafx/api/javafx/fxml/doc-files/introduction_to_fxml.html.
And the keyword controller
is not mentioned.
I only found an indication about it in the https://docs.oracle.com/javase/8/javafx/api/javafx/fxml/FXMLLoader.html#CONTROLLER_KEYWORD
My question: is this keyword controller
a feature of FXML?
Or is my syntax just a hack that works? And will this hack still work in new version of the FXMLLoader?
This is my code:
ParentPane.fxml
<?import javafx.scene.layout.VBox?>
<?import javafx.scene.control.TextField?>
<?import eu.primion.fxmlproject.fxmlview.ChildPane?>
<fx:root type="VBox" xmlns="http://javafx.com/javafx/8" xmlns:fx="http://javafx.com/fxml/1">
<children>
<ChildPane fx:id="childPane">
<viewModel>
<fx:reference source="controller.viewModel"/>
</viewModel>
</ChildPane>
</children>
</fx:root>
ParentPane.java
public class ParentPane extends VBox
{
@FXML
private ChildPane childPane;
private final ViewModel viewModel;
public ParentPane(final ViewModel viewModel)
{
this.viewModel = viewModel;
FXMLLoader fxmlLoader = new FXMLLoader(getClass().getResource("ParentPane.fxml"));
fxmlLoader.setRoot(this);
fxmlLoader.setController(this);
try
{
fxmlLoader.load();
}
catch (Exception exception)
{
throw new RuntimeException(exception);
}
}
public ViewModel getViewModel()
{
return this.viewModel;
}
}
ChildPane.fxml
<fx:root type="VBox" xmlns="http://javafx.com/javafx/8" xmlns:fx="http://javafx.com/fxml/1">
<children>
<TextField fx:id="textField" />
</children>
</fx:root>
ChildPane.java
public class ChildPane extends VBox
{
@FXML
private TextField textField;
private final ViewModel viewModel;
public ChildPane(@NamedArg("viewModel") final ViewModel viewModel)
{
this.viewModel = viewModel;
FXMLLoader fxmlLoader = new FXMLLoader(getClass().getResource("ChildPane.fxml"));
fxmlLoader.setRoot(this);
fxmlLoader.setController(this);
try
{
fxmlLoader.load();
}
catch (Exception exception)
{
throw new RuntimeException(exception);
}
}
public void initialize()
{
this.textField.textProperty().bindBidirectional(this.viewModel.textProperty());
}
}
It's not explicitly documented, but the controller is added to the FXML loader's namespace, and so it is accessible via expressions in the FXML via the expression variable
controller
. The same is true for the expression variablesresources
(which gives access to the resource bundle set on the FXML loader, or passed to theload()
method) andlocation
(which gives access to the URL representing the location of the FXML).While this isn't explicitly documented, the FXML documentation does contain an example using this technique; so it would be extremely surprising if this were changed in a future release. In general, the behavior of a
FXMLLoader
is not well documented.