绑定属性不起作用
Bound properties not working
我正在使用 TornadoFX 1.7.5,但我似乎无法使绑定属性起作用。我有以下 ItemViewModels
class DynamicMenuViewModel : ItemViewModel<DynamicMenu>(DynamicMenu()) {
val title = bind { item?.title?.toProperty() }
val isBold = bind { item?.isBold?.toProperty() }
val routes = bind { item?.routes?.toProperty() }
}
data class DynamicMenu(var title: String = "", var isBold: Boolean = false, var routes: MutableList<MenuRouteViewModel> = mutableListOf())
class MenuRouteViewModel : ItemViewModel<MenuRoute>(MenuRoute()) {
val url = bind { item?.url?.toProperty() }
val title = bind { item?.title?.toProperty() }
val isBold = bind { item?.isBold?.toProperty() }
val showNew = bind { item?.showNew?.toProperty() }
}
data class MenuRoute(var url: String = "", var title: String = "", var showNew: Boolean = false, var isBold: Boolean = false)
绑定如下:
//routesController.dynamicMenu is an instance of DynamicMenuViewModel()
textfield(property = routesController.dynamicMenu.title) {
prefWidth = formWidth * .5
gridpaneConstraints {
columnRowIndex(0, 1)
marginLeft = 10.0
columnSpan = 2
marginBottom = 20.0
}
}
checkbox(property = routesController.dynamicMenu.isBold){
gridpaneConstraints {
columnRowIndex(2, 1)
marginLeft = 15.0
marginBottom = 20.0
}
}
然后,当我单击按钮时,以下函数会提交模型并将它们打印到屏幕上:
fun onClick(){
commitModel()
println(dynamicMenu.item.toString())
dynamicMenu.item.routes.forEach {
println(it.item.toString())
}
}
fun commitModel(){
dynamicMenu.item.routes.forEach {
it.commit()
}
dynamicMenu.commit()
}
问题是当我 运行 程序编辑文本字段和复选框然后单击 运行s onClick()
按钮时,支持项似乎没有得到更新。因此 none 的更新值被打印到控制台。
我做错了什么?
您可能知道,ViewModel 只能双向绑定到 JavaFX 属性。您的域对象不包含 JavaFX 属性,因此您需要转换它们。但是,您使用的 toProperty()
函数仅对一个值进行操作,并将其转换为 属性。此 属性 无法知道它的字段所有者,因此无法写回域对象。
幸运的是,您可以使用 observable
函数使您的域对象属性也可写:
val url = bind { item?.observable(MenuRoute::url) }
由于 observable
函数在 MenuRoute
对象的特定实例上运行,它现在有足够的信息可以在您 commit()
模型时写回该实例。
如果您考虑将域对象中的属性更改为可观察的,您可以这样写:
val url = bind(MenuRoute::url)
您可以使用 TornadoFX IDEA 插件检查 "Convert all properties to TornadoFX Properties" 自动修改您的属性。这会将您的 MenuRoute
对象转换为:
class MenuRoute {
val isBoldProperty = SimpleBooleanProperty(false)
var isBold by isBoldProperty
val showNewProperty = SimpleBooleanProperty(false)
var showNew by showNewProperty
val urlProperty = SimpleStringProperty("")
var url by urlProperty
val titleProperty = SimpleStringProperty("")
var title by titleProperty
}
(您必须手动删除 class 上的 data
修饰符。还要注意当前版本的插件在转换函数中存在一个错误,该错误会保留旧参数 - a新版本即将发布)。
如果您出于各种原因不想这样做,即使对于像您这样的可变变量,我也能够支持这种很好的语法,因此从 TornadoFX 1.7.6 开始,您可以在绑定语句中使用这种语法即使您不想更改数据 classes:
val url = bind(MenuRoute::url)
我正在使用 TornadoFX 1.7.5,但我似乎无法使绑定属性起作用。我有以下 ItemViewModels
class DynamicMenuViewModel : ItemViewModel<DynamicMenu>(DynamicMenu()) {
val title = bind { item?.title?.toProperty() }
val isBold = bind { item?.isBold?.toProperty() }
val routes = bind { item?.routes?.toProperty() }
}
data class DynamicMenu(var title: String = "", var isBold: Boolean = false, var routes: MutableList<MenuRouteViewModel> = mutableListOf())
class MenuRouteViewModel : ItemViewModel<MenuRoute>(MenuRoute()) {
val url = bind { item?.url?.toProperty() }
val title = bind { item?.title?.toProperty() }
val isBold = bind { item?.isBold?.toProperty() }
val showNew = bind { item?.showNew?.toProperty() }
}
data class MenuRoute(var url: String = "", var title: String = "", var showNew: Boolean = false, var isBold: Boolean = false)
绑定如下:
//routesController.dynamicMenu is an instance of DynamicMenuViewModel()
textfield(property = routesController.dynamicMenu.title) {
prefWidth = formWidth * .5
gridpaneConstraints {
columnRowIndex(0, 1)
marginLeft = 10.0
columnSpan = 2
marginBottom = 20.0
}
}
checkbox(property = routesController.dynamicMenu.isBold){
gridpaneConstraints {
columnRowIndex(2, 1)
marginLeft = 15.0
marginBottom = 20.0
}
}
然后,当我单击按钮时,以下函数会提交模型并将它们打印到屏幕上:
fun onClick(){
commitModel()
println(dynamicMenu.item.toString())
dynamicMenu.item.routes.forEach {
println(it.item.toString())
}
}
fun commitModel(){
dynamicMenu.item.routes.forEach {
it.commit()
}
dynamicMenu.commit()
}
问题是当我 运行 程序编辑文本字段和复选框然后单击 运行s onClick()
按钮时,支持项似乎没有得到更新。因此 none 的更新值被打印到控制台。
我做错了什么?
您可能知道,ViewModel 只能双向绑定到 JavaFX 属性。您的域对象不包含 JavaFX 属性,因此您需要转换它们。但是,您使用的 toProperty()
函数仅对一个值进行操作,并将其转换为 属性。此 属性 无法知道它的字段所有者,因此无法写回域对象。
幸运的是,您可以使用 observable
函数使您的域对象属性也可写:
val url = bind { item?.observable(MenuRoute::url) }
由于 observable
函数在 MenuRoute
对象的特定实例上运行,它现在有足够的信息可以在您 commit()
模型时写回该实例。
如果您考虑将域对象中的属性更改为可观察的,您可以这样写:
val url = bind(MenuRoute::url)
您可以使用 TornadoFX IDEA 插件检查 "Convert all properties to TornadoFX Properties" 自动修改您的属性。这会将您的 MenuRoute
对象转换为:
class MenuRoute {
val isBoldProperty = SimpleBooleanProperty(false)
var isBold by isBoldProperty
val showNewProperty = SimpleBooleanProperty(false)
var showNew by showNewProperty
val urlProperty = SimpleStringProperty("")
var url by urlProperty
val titleProperty = SimpleStringProperty("")
var title by titleProperty
}
(您必须手动删除 class 上的 data
修饰符。还要注意当前版本的插件在转换函数中存在一个错误,该错误会保留旧参数 - a新版本即将发布)。
如果您出于各种原因不想这样做,即使对于像您这样的可变变量,我也能够支持这种很好的语法,因此从 TornadoFX 1.7.6 开始,您可以在绑定语句中使用这种语法即使您不想更改数据 classes:
val url = bind(MenuRoute::url)