kotlin - tornadofx listview 正在创建一个额外的空 listcellfragment,而不是列表中的项目
问题描述
我有一个 ListView 的 ViewModel,里面有 3 个玩家:
object PlayerListViewModel : ViewModel() {
lateinit var players : ObservableList<Player>
init{
}
fun loadPlayers(){
players = Engine.selectedGame.players.asObservable()
}
}
class PlayerListView : View() {
private val vm = PlayerListViewModel
override val root = VBox()
init {
vm.loadPlayers()
root.replaceChildren {
style {
spacing = 25.px
alignment = Pos.CENTER
padding = box(0.px, 15.px)
}
listview(vm.players){
style{
background = Background.EMPTY
prefWidth = 300.px
}
isFocusTraversable = false
isMouseTransparent = true
cellFragment(PlayerCardFragment::class)
}
}
}
}
由于某种原因,listview
正在创建 4 PlayerCardFragments
,第一个具有 nullitem
属性,最后 3 个具有正确的Player
项目引用。这是PlayerCardFragment
定义:
class PlayerCardFragment : ListCellFragment<Player>() {
private val logger = KotlinLogging.logger { }
private val vm = PlayerViewModel().bindTo(this)
private lateinit var nameLabel : Label
private lateinit var scoreLabel : Label
override val root = hbox {
addClass(UIAppStyle.playerCard)
nameLabel = label(vm.name) { addClass(UIAppStyle.nameLabel) }
scoreLabel = label(vm.score) { addClass(UIAppStyle.scoreLabel) }
}
init {
logger.debug { "Initializing fragment for ${this.item} and ${vm.name.value}" }
EventBus.channel(EngineEvent.PlayerChanged::class)
.observeOnFx()
.subscribe() {
vm.rollback() //force viewmodel (PlayerViewModel) refresh since model (Player) does not implement observable properties
logger.debug { "${vm.name.value}'s turn is ${vm.myTurn.value}" }
root.toggleClass(UIAppStyle.selected, vm.myTurn)
}
}
运行应用程序时,PlayerCardFragment
初始化打印四次“Initializing fragment for null and null”,但列表显示完美正确,包含 3 个 Player 项目。稍后在执行过程中,Engine.PlayerChanged
如果收到一个事件,Oberver 函数会打印:“null's turn is false”“Adam's turn is false”“Chad's turn is true”“Kyle's turn is false”这些是正确的玩家,有正确的回合状态。随着样式的变化,它listview
看起来非常好。我只是不确定第一个 null ListCellFragment 来自哪里。
解决方案
似乎您正试图ItemViewModel
通过改变它周围的一切来为视图模型提供功能。为什么不改成PlayerViewModel
拥有这个功能呢?最简单的想象方法是从泛型属性中创建绑定,然后通过监听将它们全部更改并提交itemProperty
:
class Player(var foo: String?, var bar: Int?)
class PlayerViewModel() : ItemViewModel<Player>() {
val foo = bind { SimpleStringProperty() }
val bar = bind { SimpleIntegerProperty() }
init {
itemProperty.onChange {
foo.value = it?.foo
bar.value = it?.bar
}
}
override fun onCommit() {
item?.let { player ->
player.foo = foo.value
player.bar = bar.value?.toInt()
}
}
}
漂亮吗?不。它是否使您不必实施事件系统?是的。
推荐阅读
- javascript - 我如何处理在 redux saga 中调用不同函数的多个动作?
- c# - 如何访问某个按钮以更改某个文本字段的值(在动态创建的控件中)
- liquibase - Liquibase:删除重复行
- php - Lumen 中未找到特征“App\HasApiTokens”
- python - Python:熊猫数据框根据列中整数的最后三位重新排列行
- google-api - Google API 更新产品详情
- java - 如何回滚分支的最后一次提交?
- laravel - Laravel Homestead 是否安装了 Nginx 或 Apache?
- ios - 快速更新键盘预测栏建议
- python - 如何为我的 __dict__ 属性推广此功能