Die Grundidee besteht darin, ein einziges Datenmodell zu verwenden, das unter den Komponenten aufgeteilt ist, die auf gemeinsam genutzte Daten zugreifen müssen. Die Verwendung von @Inject
in afterburner.fx bietet eine bequeme Möglichkeit, dies für Sie zu verwalten.
Bei Entwurfsmustern ist zunächst zu beachten, dass afterburner.fx (und in geringerem Maße vielleicht auch der FXML- "Controller" -Mechanismus im Allgemeinen) tatsächlich auf einem MVP-Muster basiert (kein MVVM-Muster). . Die FXML-Datei repräsentiert die (passive) Ansicht; Der Präsentator ist natürlich der Moderator und das Modell wird entsprechend den Anwendungsanforderungen implementiert.
Normalerweise ist das Framework, das Sie verwenden, ein großer Teil der Entscheidung, welche Muster zu verwenden sind, daher denke ich, dass meine wichtigste Empfehlung darin besteht, ein MVP-Muster zu verwenden. Mit MVP, das sieht wie folgt aus:
Sie können ein ObservableList
in Ihrem Modell erstellen:
public class Model {
private final ObservableList<String> itemList = FXCollections.observableArrayList();
public ObservableList<String> getItemList() {
return itemList ;
}
}
Dann in dem Moderator für die Ansicht, dass die ListView
hat, tun:
public class ListPresenter {
@Inject
private Model model ;
@FXML
private ListView<String> listView ;
@FXML
public void initialize() {
listView.setItems(model.getItemList());
}
}
so dass das ListView
das ObservableList
im Modell für seine Unterstützungsliste von Einzelteilen verwendet. Dies bedeutet, dass sich die ListView
automatisch aktualisiert, wenn sich diese Liste ändert.
In den Vortragenden für die Ansicht, dass das Textfeld hat, was Sie tun:
public class AddItemPresenter {
@Inject
private Model model ;
@FXML
private TextField textField ;
// handler for button press:
@FXML
private void handleButton() {
model.getItemList().add(textField.getText());
}
}
Nun, wenn die Taste gedrückt wird, wird der Text in das Textfeld ein, um die Artikelliste des Modells hinzugefügt. Da Sie diese Liste als Hintergrundliste für die Listenansicht festlegen, wird der Text in der Listenansicht angezeigt.
Wenn Sie hier ein MVVM Muster zu zwingen, ich glaube, Sie haben wie umfassend das FXML-Moderator Paar von Nachbrenner „Ansicht“ in MVVM zu betrachten. Sie erhalten also etwas, das wie ein M (VP) VM-Muster aussieht. Ich bin mit MVVM nicht so vertraut wie mit MVC und MVP, aber nach meinem Verständnis gibt es drei Komponenten: das bekannte Datenmodell (M), die Ansicht (V) und das Ansichtsmodell (VM). Die Rolle des Ansichtsmodells besteht darin, den Zustand der Ansicht einschließlich der Aktionen darzustellen, aber es weiß nichts über die tatsächliche Ansicht selbst. Im obigen Beispiel hätten Sie zwei Ansichtsmodelle. eine für jede der Ansichten. Beachten Sie, dass ein Datenmodell (M) noch vorhanden ist und die Ansichtsmodelle natürlich Zugriff darauf benötigen.Sie müssen dieselbe Datenmodellinstanz verwenden, damit dieselben Daten darauf zugreifen und dieselben Daten bearbeiten können.
Ich denke, eine Implementierung dieser sieht aus wie
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);
}
}
Die Model
Klasse die gleiche wie zuvor. Die Aufgabe des Moderators (Blick in MVVM) ist die Ansicht auf die Ansicht Modell zu binden:
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());
}
}
ähnlich das View-Modell für das Modul "add Punkt" sieht aus wie
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("");
}
}
und die AddItemPresenter
jetzt sieht aus wie
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());
}
}
der hier Effekt wirklich nur ist eine zusätzliche Schicht zwischen der Ansicht und dem (Daten) Modell einzufügen. Der Nettoeffekt fühlt sich an, als würde der Moderator nicht wirklich "an seinem Gewicht" ziehen, was normalerweise ein Anzeichen dafür ist, dass die Anwendung überdimensioniert ist und zu viele Schichten hat. Sie haben jedoch den Vorteil, dass das View-Modell jetzt viel "testfreundlicher" ist als der Presenter (und dies kann natürlich durch Bereitstellung eines Setter- oder Konstruktor-Parameters für das injizierte Modell noch verbessert werden).
Danke für die Antwort, aber ich interpretiere die Moderatoren als die Ansichten im Model-View-ViewModel-Prinzip. Sie haben also keine View-Logik. Sie verbinden nur die Ansichtselemente wie das ListView mit dem ViewModel. In dem Beispiel haben die Presenter Logik listView.setItems (model.getItemList()); model.getItemList(). Add (textField.getText()); und das ist nicht wirklich testfreundlich (weil @Inject und @FXML). Meiner Meinung nach müssen die Viewmodels mit dieser Kommunikation umgehen. Ist das eine falsche Überlegung? THX – user2558928
@ user2558928 Das zugrunde liegende Muster, das von afterburner.fx verwendet wird, ist ein MVP (passive view) -Muster (das ist ziemlich wahr, wenn Sie auch FXML und "Controller" -Klassen verwenden). Einen MVVM-Entwurf darüber hinaus zu erzwingen, wird schwierig werden - Sie würden mit einer Art M (VP) VM Design enden. Vielleicht könnten Sie Ihrer Frage Code hinzufügen, um zu zeigen, von was Sie ausgehen? –
@ user2558928 Siehe Update mit einem MVVM-Ansatz (denke ich ...). –