将值从ViewModel传输到另一个ViewModel(JavaFX,mvvm,afterburner.fx)

时间:2017-05-04 22:20:02

标签: java javafx mvvm

我想用JavaFX创建一个应用程序,我遇到了分离视图(由afterburner.fx分割)和mvvm主体的问题。 在我的场景中,我有一个带有文本字段和按钮的视图和带有列表视图的第二个视图。 现在我在文本字段中编写一些文本,通过单击按钮将文本添加到列表中。 我有四个类(textfield / button和list的视图和视图模型)。 现在问题是:我如何对按钮进行反应并将文本从文本字段传输到列表?

我可以绑定视图中的文本和viewModel中的属性。但是如何将值传递给列表的viewmodel?

我希望有人可以帮助我解决这个理解问题。

非常感谢!

1 个答案:

答案 0 :(得分:0)

这里的基本思想是使用单个数据模型,该模型在需要访问共享数据的组件之间共享。在afterburner.fx中使用@Inject将为您提供一种方便的方法来管理它。

对于设计模式,首先要注意的是afterburner.fx(在较小程度上,也许,FXML - "控制器"机制一般)实际上是基于MVP模式(不是MVVM模式)。 FXML文件代表(被动)视图;演示者当然是演示者,模型是根据应用要求实现的。

通常,您使用的框架是决定使用哪种模式的重要部分,所以我认为我的主要建议是在这里使用MVP模式。使用MVP,如下所示:

您可以在模型中创建ObservableList

public class Model {

    private final ObservableList<String> itemList = FXCollections.observableArrayList();

    public ObservableList<String> getItemList() {
        return itemList ;
    }

}

然后在具有ListView的视图的演示者中,执行:

public class ListPresenter {

    @Inject
    private Model model ;

    @FXML
    private ListView<String> listView ;

    @FXML
    public void initialize() {
        listView.setItems(model.getItemList());
    }
}

以便ListView使用模型中的ObservableList作为其项目的后备列表。这意味着如果该列表发生更改,则ListView将自动更新。

在包含文本字段的视图的演示者中,您执行以下操作:

public class AddItemPresenter {

    @Inject
    private Model model ;

    @FXML
    private TextField textField ;

    // handler for button press:
    @FXML
    private void handleButton() {
        model.getItemList().add(textField.getText());
    }
}

现在按下按钮时,文本字段中的文本将添加到模型的项目列表中。因为您将该列表设置为列表视图的后备列表,所以文本将显示在列表视图中。

如果你想在这里强制使用MVVM模式,我认为你必须考虑&#34; View&#34;在MVVM中包含来自加力燃烧室的FXML-presenter对。因此,您最终得到的东西看起来像M(VP)VM模式。我不像MVC和MVP那样熟悉MVVM,但据我所知,它有三个组件:熟悉的数据模型(M),视图(V)和视图模型(VM)。视图模型的作用是表示视图的状态,包括操作,但它对实际视图本身一无所知。在上面的示例中,您将拥有两个视图模型;每个观点一个。请注意,数据模型(M)仍然存在,当然视图模型需要访问它。他们需要共享相同的数据模型实例,以便他们可以访问和操作相同的数据。

我认为这个实现看起来像

public class ListViewModel {

    @Inject
    private Model model ;

    private final StringProperty selectedItem = new SimpleStringProperty();

    public ObservableList<String> getItems() {
        return model.getItemList();
    }

    public StringProperty selectedItemProperty() {
        return selectedItem ;
    }

    public String getSelectedItem() {
        return selectedItemProperty().get();
    }

    public void setSelectedItem(String item) {
        selectedItemProperty().set(item);
    }
}

Model类和以前一样。演示者的工作(MVVM中的视图)是将视图绑定到视图模型:

public class ListViewPresenter {

    @Inject
    private ListViewModel viewModel ;

    @FXML
    private ListView<String> listView ;

    @FXML
    public void initialize() {
        listView.setItems(viewModel.getItems());
        viewModel.selectedItemProperty().bind(listView.getSelectionModel().selectedItemProperty());
    }
}

类似于&#34;添加项目的视图模型&#34;模块看起来像

public class AddItemViewModel {

    @Inject 
    private Model model ;

    private final StringProperty currentItem = new SimpleStringProperty();

    private final Runnable addItemAction = this::addItem ;

    public StringProperty currentItemProperty() {
        return currentItem ;
    }

    public String getCurrentItem() {
        return currentItemProperty().get();
    }

    public void setCurrentItem(String item) {
        currentItemProperty().set(item);
    }

    public Runnable getAddItemAction() {
        return addItemAction ;
    }

    private void addItem() {
        model.getItemList().add(getCurrentItem());
        setCurrentItem("");
    }
}

AddItemPresenter现在看起来像

public class AddItemPresenter {

    @Inject
    private AddItemViewModel viewModel ;

    @FXML
    private TextField textField ;

    @FXML
    private Button addButton ;

    @FXML
    public void initialize() {
        viewModel.currentItemProperty().bindBidirectional(textField.textProperty());
        addButton.setOnAction(e -> viewModel.getAddItemAction().run());
    }
}

这里的效果实际上只是在视图和(数据)模型之间插入一个附加层。净效果感觉好像主持人现在并没有真正地减轻它的重量,这通常表明应用程序过度设计并且层数太多。但是,您确实获得了一个优势,因为视图模型现在更加适合测试并且#34;而不是演示者(当然,通过为注入的模型提供setter或构造函数参数可以做得更多)。