Начнем с наиболее явного способа передачи данных во фрагменты. В этом примере TableView вы можете открыть наблюдаемый список внутри фрагмента и связать свой TableView с этим списком. Затем вы можете обновить этот список вне фрагмента, и ваши изменения будут отражены во фрагменте. В этом примере я создал простой объект данных с наблюдаемым свойством SomeItem
:
class SomeItem(name: String) {
val nameProperty = SimpleStringProperty(name)
var name by nameProperty
}
Теперь мы можем определить SomeViewFragment
со свойством элемента, привязанным к TableView:
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 в наш фрагмент и извлекаем элементы из этой модели:
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 в руководстве:
Области
EventBus
ViewModel и Validation а>
person
Edvin Syse
schedule
17.12.2016