javafxmvvmmvvmfx

mvvmFX: Changing Part of a Scene on Runtime


I'm building a JavaFX Application with mvvmFX.

I have a scene with two panes. Both panes should include any.fxml . I would like to change the included panes at runtime.

picture

So I've found this solution: JavaFX/SceneBuilder - Changing only PART of a Scene and tried to apply it.

So far, so good. Pane2 is displaying any.fxml, but unfortunately, the controller/viewModel is not getting loaded. At least it seems so, any.fxml contains a label which should get modified by the viewModel.

If O add fx:controller="anyVM" to any.fxml and include it via fx:include source="any.fxml" in pane2.fxml everything is working fine. But it's important for me to change it on runtime.

I would be glad if somebody knows a solution how to achieve this.

This is the View of my Main-Scene:

public class Scene implements FxmlView<SceneVM>, Initializable {    
    @FXML
    private BorderPane pane2;

    @InjectViewModel
    private SceneVM sceneVM;

    @Override
    public void initialize(URL url, ResourceBundle resourceBundle) {    
        FXMLLoader loader = new FXMLLoader(getClass().getResource("any.fxml"));
        loader.setController(anyVM.class);

        try {
            pane2.setCenter(loader.load());
        } catch (IOException e) {
            e.printStackTrace();
        }
    } 
}     

This is pane2 in scene.fxml:

<BorderPane fx:id="pane2" layoutX="846.0" prefHeight="547.0" prefWidth="521.0">
    <center>            <!--<fx:include source="any.fxml" />-->
    </center>
</BorderPane>

This is the ViewModel / Controller

@Singleton
public class anyVM implements ViewModel {    
    private StringProperty lbl = new SimpleStringProperty("27");

    public StringProperty getLbl(){
        return basementViewKesselTempLbl;
    }

    public void setLbl(String message){
        lbl.set(message);
    }    
}

Solution

  • In your example code of initialize you are using FXMLLoader which is part of standard JavaFX. However, to load a mvvmFX View with all setup logic you have to use mvvmFX's FluentViewLoader. The FluentViewLoader uses FXMLLoader internally but does a whole lot more operations like injecting ViewModels into their Views.

    So your code should look like this:

    @Override
    public void initialize(URL url, ResourceBundle resourceBundle) {
        ViewTuple<AnyView, AnyViewModel> viewTuple = FluentViewLoader.fxmlView(AnyView.class).load();
    
        pane2.setCenter(viewTuple.getView());  
    }