Tornadofx - 如何在每个实例上将参数传递给Fragment [英] Tornadofx - How to pass parameter to Fragment on every instance

查看:456
本文介绍了Tornadofx - 如何在每个实例上将参数传递给Fragment的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我是javafx,kotlin和明显tornadofx的新手。

问题

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

I am a newbie to javafx, kotlin and obviously tornadofx.
Issue:
How to pass parameters to Fragment on every instance?

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

Lets say I have a table view layout as my fragment. Now this fragment is used at multiple places but with different datasets.

例如。
添加片段:

eg. Adding a fragment in:

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

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

声明片段:

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

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

How can I pass different someDataSetFromRestApiCall from SomeView and SomeAnotherView ?

推荐答案

让我们从最明确的方式开始将数据传递给Fragments。对于此TableView示例,您可以在Fragment中公开一个可观察列表,并将TableView绑定到此列表。然后,您可以从片段外部更新该列表,并将更改反映在片段中。对于该示例,我创建了一个简单的数据对象,其中包含一个名为 SomeItem 的可观察属性:

Let's start with the most explicit way to pass data to Fragments. For this TableView example you could expose an observable list inside the Fragment and tie your TableView to this list. Then you can update that list from outside the Fragment and have your changes reflected in the fragment. For the example I created a simple data object with an observable property called SomeItem:

class SomeItem(name: String) {
    val nameProperty = SimpleStringProperty(name)
    var name by nameProperty
}

现在我们可以使用绑定到TableView的item属性定义 SomeViewFragment

Now we can define the SomeViewFragment with an item property bound to the TableView:

class SomeViewFragment : Fragment() {
    val items = FXCollections.observableArrayList<SomeItem>()

    override val root = tableview(items) {
        column("Name", SomeItem::nameProperty)
    }
}

如果您稍后更新商品内容,更改将反映在表格中:

If you later update the items content, the changes will be reflected in the table:

class SomeView : View() {
    override val root = stackpane {
        this += find<SomeViewFragment>().apply {
            items.setAll(SomeItem("Item A"), SomeItem("Item B"))
        }
    }
}

然后你可以为<$ c做同样的事情$ c> SomeOtherView 但包含其他数据:

You can then do the same for SomeOtherView but with other data:

class SomeOtherView : View() {
    override val root = stackpane {
        this += find<SomeViewFragment>().apply {
            items.setAll(SomeItem("Item B"), SomeItem("Item C"))
        }
    }
}

虽然这很容易理解且非常明确,它在您的组件之间创建了一个非常强大的耦合。您可能需要考虑使用范围。我们现在有两个选择:

While this is easy to understand and very explicit, it creates a pretty strong coupling between your components. You might want to consider using scopes for this instead. We now have two options:


  1. 在范围内使用注入

  2. 让范围包含数据



在范围内使用注入



我们将首先使用选项1 ,通过注入数据模型。我们首先创建一个可以保存项目列表的数据模型:

Use injection inside the scope

We will go with option 1 first, by injecting the data model. We first create a data model that can hold our items list:

class ItemsModel(val items: ObservableList<SomeItem>) : ViewModel()

现在我们将这个ItemsModel注入我们的Fragment并从该模型中提取项目:

Now we inject this ItemsModel into our Fragment and extract the items from that model:

class SomeViewFragment : Fragment() {
    val model: ItemsModel by inject()

    override val root = tableview(model.items) {
        column("Name", SomeItem::nameProperty)
    }
}

最后,我们需要为每个视图中的片段定义一个单独的范围,并为该范围准备数据:

Lastly, we need to define a separate scope for the fragments in each view and prepare the data for that scope:

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中提供。同时您可以使用:

Please not that the setInScope function used above will be available in TornadoFX 1.5.9. In the mean time you can use:

FX.getComponents(fragmentScope).put(ItemsModel::class, model)



让范围包含数据



另一种选择是将数据直接放入范围。让我们创建一个 ItemsScope

class ItemsScope(val items: ObservableList<SomeItem>) : Scope()

现在我们的片段将获得<$ c的实例$ c> SomeItemScope 所以我们将其转换并提取数据:

Now our fragment will expect to get an instance of SomeItemScope so we cast it and extract the data:

class SomeViewFragment : Fragment() {
    override val scope = super.scope as ItemsScope

    override val root = tableview(scope.items) {
        column("Name", SomeItem::nameProperty)
    }
}

View现在需要做的工作少,因为我们不需要需要模型:

The View needs to do less work now since we don't need the model:

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



传递参数



编辑:由于这个问题,我们决定包含对使用查找传递参数的支持和注入。从TornadoFX 1.5.9开始,您可以将项目列表作为参数发送,如下所示:

Passing parameters

EDIT: As a result of this question, we decided to include support for passing parameters with find and inject. From TornadoFX 1.5.9 you can therefore send the items list as a parameter like this:

class SomeView : View() {
    override val root = stackpane {
        val params = "items" to listOf(SomeItem("Item A"), SomeItem("Item B")).observable()
        this += find<SomeViewFragment>(params)
    }
}

SomeViewFragment 现在可以获取这些参数并直接使用它们:

The SomeViewFragment can now pick up these parameters and use them directly:

class SomeViewFragment : Fragment() {
    val items: ObservableList<SomeItem> by param()

    override val root = tableview(items) {
        column("Name", SomeItem::nameProperty)
    }
}

请注意,这不涉及片段中未经检查的演员表。

Please not that this involves an unchecked cast inside the Fragment.

您还可以通过EventBus传递参数和数据,这也将在即将发布的TornadoFX 1.5.9中传递。 EventBus还支持范围,可以轻松定位您的活动。

You could also pass parameters and data over the EventBus, which will also be in the soon to be released TornadoFX 1.5.9. The EventBus also supports scopes which makes it easy to target your events.

您可以阅读更多关于指南中的Scopes,EventBus和ViewModel:

You can read more about Scopes, EventBus and ViewModel in the guide:

Scopes

EventBus

ViewModel and Validation

这篇关于Tornadofx - 如何在每个实例上将参数传递给Fragment的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆