2017-05-04 27 views
0

我想創建與JavaFX的一個應用程序和我有分離的視圖(由afterburner.fx splited)和MVVM主要的問題。 在我的情況下,我有一個視圖與文本框和按鈕和第二個視圖與列表視圖。 現在我在文本框中寫入一些文本,通過單擊按鈕將文本添加到列表中。 我有四個類(文本框/按鈕和列表的視圖和視圖模型)。 現在的問題是:我如何對buttonclick做出反應並將文本從文本字段傳輸到列表中?從視圖模型的值轉移到另一個視圖模型(JavaFX的,MVVM,afterburner.fx)

我可以綁定視圖中的文本和viewModel中的一個屬性。但是,我如何將值傳遞給列表的視圖模型?

我希望有人能幫助我理解這個問題。

非常感謝!

回答

0

這裏的基本思路是使用單個數據模型,它在需要訪問共享數據的組件之間共享。在afterburner.fx中使用@Inject將爲您提供一種便捷的管理方法。

對於設計模式,首先要注意的是,afterburner.fx(也可能是一般的FXML-「controller」機制)實際上是基於MVP模式(而不是MVVM模式) 。 FXML文件表示(被動)視圖;主講人當然是主持人,模型是根據應用需求來實現的。

通常,您使用的框架是決定使用哪種模式的重要部分,所以我認爲我的主要建議是在這裏使用MVP模式。使用MVP,這看起來像下面這樣:

您可以在模型中創建一個ObservableList:在主持人的具有ListView認爲

public class Model { 

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

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

} 

然後執行:

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模式,我認爲你必須考慮MVVM「查看」爲包括從加力FXML,主持人對。所以你最終得到的是一個看起來像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()); 
    } 
} 

同樣爲「添加項目」模塊視圖模型看起來像

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()); 
    } 
} 

這裏的效果實際上只是在視圖和(數據)模型之間插入一個附加層。實際效果就好像主持人現在沒有真正「拉開重量」,這通常表明應用程序設計過度,層數過多。但是,您確實獲得了優勢,因爲視圖模型現在比演示者更「測試友好」(當然,通過爲注入的模型提供setter或構造函數參數可以使其更加有效)。

+0

感謝您的回答,但我將演示者解釋爲Model-View-ViewModel原理中的視圖。所以他們沒有任何查看邏輯。 它們只將視圖元素(如ListView)與ViewModel連接起來。 在示例中,Presenter具有邏輯 listView.setItems(model.getItemList()); model.getItemList()。add(textField.getText()); 並且這不是真的測試友好(因爲@Inject和@FXML)。 在我看來,視圖模型必須處理這種交流。 這是一個錯誤的審議? THX – user2558928

+0

@ user2558928 afterburner.fx使用的底層模式是MVP(被動視圖)模式(如果使用FXML和「控制器」類,這也是非常正確的)。在這之上強制設計一個MVVM設計將會非常棘手 - 您最終會得到某種M(VP)VM設計。也許你可以在你的問題中添加一些代碼來顯示你從哪裏開始? –

+0

@ user2558928查看MVVM方法的更新(我認爲...)。 –