[英]Tornadofx - How to pass parameter to Fragment on every instance
我是javafx,kotlin和明顯tornadofx的新手。
問題 :
如何在每個實例上將參數傳遞給Fragment?
假設我有一個表視圖布局作為我的片段。 現在,此片段在多個位置使用,但具有不同的數據集。
例如。 添加片段:
class SomeView : View() {
...
root += SomeViewFragment::class
}
class SomeAnotherView : View() {
...
root += SomeViewFragment::class
}
聲明片段:
class SomeViewFragment : Fragment() {
...
tableview(someDataSetFromRestApiCall) {
...
}
}
如何從SomeView和SomeAnotherView傳遞不同的someDataSetFromRestApiCall?
讓我們從最明確的方式將數據傳遞給Fragments開始。 對於此TableView示例,您可以在Fragment中公開一個可觀察列表,並將TableView綁定到此列表。 然后,您可以從片段外部更新該列表,並將更改反映在片段中。 在這個例子中,我創建了一個帶有名為SomeItem
的可觀察屬性的簡單數據對象:
class SomeItem(name: String) {
val nameProperty = SimpleStringProperty(name)
var name by nameProperty
}
現在我們可以使用綁定到TableView的item屬性定義SomeViewFragment
:
class SomeViewFragment : Fragment() {
val items = FXCollections.observableArrayList<SomeItem>()
override val root = tableview(items) {
column("Name", SomeItem::nameProperty)
}
}
如果您以后更新項目內容,更改將反映在表格中:
class SomeView : View() {
override val root = stackpane {
this += find<SomeViewFragment>().apply {
items.setAll(SomeItem("Item A"), SomeItem("Item B"))
}
}
}
然后,您可以對SomeOtherView
執行相同操作,但使用其他數據:
class SomeOtherView : View() {
override val root = stackpane {
this += find<SomeViewFragment>().apply {
items.setAll(SomeItem("Item B"), SomeItem("Item C"))
}
}
}
雖然這很容易理解且非常明確,但它會在您的組件之間創建非常強大的耦合。 您可能需要考慮使用范圍。 我們現在有兩個選擇:
我們將首先使用選項1,通過注入數據模型。 我們首先創建一個可以保存項目列表的數據模型:
class ItemsModel(val items: ObservableList<SomeItem>) : ViewModel()
現在我們將這個ItemsModel注入到Fragment中並從該模型中提取項目:
class SomeViewFragment : Fragment() {
val model: ItemsModel by inject()
override val root = tableview(model.items) {
column("Name", SomeItem::nameProperty)
}
}
最后,我們需要為每個視圖中的片段定義一個單獨的范圍,並為該范圍准備數據:
class SomeView : View() {
override val root = stackpane {
// Create the model and fill it with data
val model= ItemsModel(listOf(SomeItem("Item A"), SomeItem("Item B")).observable())
// Define a new scope and put the model into the scope
val fragmentScope = Scope()
setInScope(model, fragmentScope)
// Add the fragment for our created scope
this += find<SomeViewFragment>(fragmentScope)
}
}
請注意,上面使用的setInScope
函數將在TornadoFX 1.5.9中可用。 同時您可以使用:
FX.getComponents(fragmentScope).put(ItemsModel::class, model)
另一種選擇是將數據直接放入范圍。 讓我們創建一個ItemsScope
:
class ItemsScope(val items: ObservableList<SomeItem>) : Scope()
現在我們的片段將獲得SomeItemScope
的實例,因此我們將其轉換並提取數據:
class SomeViewFragment : Fragment() {
override val scope = super.scope as ItemsScope
override val root = tableview(scope.items) {
column("Name", SomeItem::nameProperty)
}
}
由於我們不需要模型,View現在需要做更少的工作:
class SomeView : View() {
override val root = stackpane {
// Create the scope and fill it with data
val itemsScope= ItemsScope(listOf(SomeItem("Item A"), SomeItem("Item B")).observable())
// Add the fragment for our created scope
this += find<SomeViewFragment>(itemsScope)
}
}
編輯 :作為這個問題的結果,我們決定包括使用find
和inject
傳遞參數的支持。 從TornadoFX 1.5.9開始,您可以將項目列表作為參數發送,如下所示:
class SomeView : View() {
override val root = stackpane {
val params = "items" to listOf(SomeItem("Item A"), SomeItem("Item B")).observable()
this += find<SomeViewFragment>(params)
}
}
SomeViewFragment
現在可以獲取這些參數並直接使用它們:
class SomeViewFragment : Fragment() {
val items: ObservableList<SomeItem> by param()
override val root = tableview(items) {
column("Name", SomeItem::nameProperty)
}
}
請注意,這不涉及片段內的未經檢查的演員。
您還可以通過EventBus傳遞參數和數據,這也將在即將發布的TornadoFX 1.5.9中傳遞。 EventBus還支持范圍,可以輕松定位您的事件。
您可以在指南中閱讀有關Scopes,EventBus和ViewModel的更多信息:
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.