Tornadofx - 如何在每个实例上将参数传递给Fragment

时间:2016-12-17 11:36:24

标签: javafx kotlin tornadofx

我是javafx,kotlin和明显tornadofx的新手 问题
如何在每个实例上将参数传递给Fragment?

假设我有一个表视图布局作为我的片段。现在,这个片段在多个地方使用但具有不同的数据集。

例如。 在:

中添加片段
class SomeView : View() {
... 
root += SomeViewFragment::class
}

class SomeAnotherView : View() {
... 
root += SomeViewFragment::class
}

声明碎片:

class SomeViewFragment : Fragment() {
...
    tableview(someDataSetFromRestApiCall) {
    ...
    }
}

如何从SomeView和SomeAnotherView传递不同的someDataSetFromRestApiCall?

1 个答案:

答案 0 :(得分:12)

让我们以最明确的方式将数据传递给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. 让范围包含数据
  3. 在范围内使用注入

    我们将首先使用选项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的更多信息:

    Scopes

    EventBus

    ViewModel and Validation