关于 DI、ViewModel 等的问题
questions about DI, ViewModel etc
我有以下代码:
class ExampleView :View("My Example view") {
val model:ExampleModel by inject()
override val root= vbox {
textfield(model.data)
button("Commit") {
setOnAction {
model.commit()
closeModal()
}
}
button("Rollback") {
setOnAction {
model.rollback()
closeModal()
}
}
button("Just quit") {
setOnAction {
closeModal()
}
}
}
}
class Example() {
var data by property<String>()
fun dataProperty() = getProperty(Example::data)
}
class ExampleModel(example: Example) : ItemViewModel<Example>() {
init {
item = example
}
val data = bind { item?.dataProperty() }
}
class MainView : View() {
val example:Example
override val root = BorderPane()
init {
example = Example()
example.data = "Data for example"
val exampleModel = ExampleModel(example)
with(root){
top {
menubar {
menu("Test") {
menuitem("Example - 1") {
val scope = Scope()
setInScope(exampleModel, scope)
find<ExampleView>(scope).openWindow()
}
menuitem("Example - 2") {
val scope = Scope()
setInScope(exampleModel, scope)
find<ExampleView>(scope).openWindow()
}
}
}
}
}
}
}
对于这个例子我有两个问题:
1) 如果我更改值并在没有提交的情况下关闭 window(用户可以使用帮助 [X] 按钮执行此操作),那么只有 ViewModel 将存储更改(并且它甚至会显示在 GUI 中重新打开后),但模型 POJO 对象将保留旧数据。
如果我使用示例 class 的实例(没有 DI),那么这个实例会立即收到所有更改。
例如,我不想要 commit/rollback 功能,但我想要 DI 和即时更新。我该做什么? (当然我可以为 "textfield change value event" 调用 "commit")
2) ViewModel 具有带参数的构造函数,如果我尝试像这样打开 ExampleView
find<ExampleView>(Scope()).openWindow()
然后我得到了一个明显的 RuntimeException。例如,我可以通过编译器警告(或其他方式)避免这种情况吗?
1) 这是 ViewModel 的正确默认行为。如果将视图模型的 属性 绑定到输入,更改会立即反映在该绑定 属性 中,但只有在提交后才会刷新到基础模型对象中。
如果您想将视图模型属性中的更改自动提交回基础模型对象,您可以创建绑定并将 autocommit
属性 设置为 true:
val data = bind(true) { item?.dataProperty() }
如果您觉得更清楚的话,您也可以写成 bind(autocommit = true)
。这将导致任何更改自动刷新回基础对象。
我还想让你知道,通过在你的视图模型的构造函数中要求一个项目,你有效地防止它被用于注入,除非你像使用 setInScope
一样启动它。这可能适合您的用例,但值得注意。
2) 如果您忘记传递参数,即将推出的 TornadoFX 1.5.10 将为您提供更好的 runtime 错误消息。它还引入了参数的默认值。有关详细信息,请参阅 https://github.com/edvin/tornadofx/pull/227。
我有以下代码:
class ExampleView :View("My Example view") {
val model:ExampleModel by inject()
override val root= vbox {
textfield(model.data)
button("Commit") {
setOnAction {
model.commit()
closeModal()
}
}
button("Rollback") {
setOnAction {
model.rollback()
closeModal()
}
}
button("Just quit") {
setOnAction {
closeModal()
}
}
}
}
class Example() {
var data by property<String>()
fun dataProperty() = getProperty(Example::data)
}
class ExampleModel(example: Example) : ItemViewModel<Example>() {
init {
item = example
}
val data = bind { item?.dataProperty() }
}
class MainView : View() {
val example:Example
override val root = BorderPane()
init {
example = Example()
example.data = "Data for example"
val exampleModel = ExampleModel(example)
with(root){
top {
menubar {
menu("Test") {
menuitem("Example - 1") {
val scope = Scope()
setInScope(exampleModel, scope)
find<ExampleView>(scope).openWindow()
}
menuitem("Example - 2") {
val scope = Scope()
setInScope(exampleModel, scope)
find<ExampleView>(scope).openWindow()
}
}
}
}
}
}
}
对于这个例子我有两个问题:
1) 如果我更改值并在没有提交的情况下关闭 window(用户可以使用帮助 [X] 按钮执行此操作),那么只有 ViewModel 将存储更改(并且它甚至会显示在 GUI 中重新打开后),但模型 POJO 对象将保留旧数据。
如果我使用示例 class 的实例(没有 DI),那么这个实例会立即收到所有更改。
例如,我不想要 commit/rollback 功能,但我想要 DI 和即时更新。我该做什么? (当然我可以为 "textfield change value event" 调用 "commit")
2) ViewModel 具有带参数的构造函数,如果我尝试像这样打开 ExampleView
find<ExampleView>(Scope()).openWindow()
然后我得到了一个明显的 RuntimeException。例如,我可以通过编译器警告(或其他方式)避免这种情况吗?
1) 这是 ViewModel 的正确默认行为。如果将视图模型的 属性 绑定到输入,更改会立即反映在该绑定 属性 中,但只有在提交后才会刷新到基础模型对象中。
如果您想将视图模型属性中的更改自动提交回基础模型对象,您可以创建绑定并将 autocommit
属性 设置为 true:
val data = bind(true) { item?.dataProperty() }
如果您觉得更清楚的话,您也可以写成 bind(autocommit = true)
。这将导致任何更改自动刷新回基础对象。
我还想让你知道,通过在你的视图模型的构造函数中要求一个项目,你有效地防止它被用于注入,除非你像使用 setInScope
一样启动它。这可能适合您的用例,但值得注意。
2) 如果您忘记传递参数,即将推出的 TornadoFX 1.5.10 将为您提供更好的 runtime 错误消息。它还引入了参数的默认值。有关详细信息,请参阅 https://github.com/edvin/tornadofx/pull/227。