tornadofx listview создает один дополнительный пустой фрагмент списка, чем элементы в списке - PullRequest
0 голосов
/ 18 июня 2020

У меня есть ViewModel для ListView с 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, причем первый имеет свойство null item и последние 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 распечатывает «Инициализация фрагмента для null и null» четыре раза, но список отображается совершенно правильно с 3 Player Предметы. Позже во время выполнения, если будет получено событие Engine.PlayerChanged, функция Oberver напечатает: «ход нуля - ложь» «ход Адама - ложь» «ход Чада - истина» «ход Кайла - ложь» Это правильные игроки, с правильные статусы поворота. listview отлично выглядит с изменениями стиля. Я просто не уверен, откуда взялся этот первый нулевой ListCellFragment.

1 Ответ

0 голосов
/ 17 июля 2020

Похоже, вы пытаетесь придать ItemViewModel функциональность модели представления, изменив все вокруг. Почему бы вместо этого не изменить PlayerViewModel, чтобы иметь функциональность? Самый простой способ представить - создать привязки из общих свойств c, а затем изменить их и зафиксировать с помощью прослушивания 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()
        }
    }
}

Красиво? Нет. Это избавляет вас от необходимости внедрять систему событий? Да.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...