簡體   English   中英

Tornadofx - 如何在每個實例上將參數傳遞給Fragment

[英]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. 在范圍內使用注射
  2. 讓范圍包含數據

在范圍內使用注射

我們將首先使用選項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)
    }
}

傳遞參數

編輯 :作為這個問題的結果,我們決定包括使用findinject傳遞參數的支持。 從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的更多信息:

領域

EventBus

ViewModel和驗證

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM