简体   繁体   中英

How to update ItemFragment when item property changes

I'm quite confused about the relationship between an ItemViewModel and its underlying item. I'm trying to show a badge on the screen, and then if the badge is "achieved" on another thread, the badge should update on screen.

Right now, the badge code looks like this:

class Badge {
  val achievedProperty = SimpleBooleanProperty(this, "achieved", false)
  var achieved by achievedProperty
}

class BadgeModel: ItemViewModel<Badge>() {
  val achieved = bind(Badge::achievedProperty)
}

Next, I want to display it on the screen, in an ItemFragment subclass:

class BadgeFragment(badge: Badge): ItemFragment<Badge>() {

  private val model: BadgeModel by inject()
  
  init {
    model.item = badge
  }

  override val root = rectangle {
    width = 50
    height = 50
    stroke = Color.BLACK
    fill = if (model.achieved) Color.RED else Color.GREEN
  }
}

This works fine to start, but if I then set badge.achieved = true (in my controller), the color of the badge on screen doesn't change.

I'm clearly missing something about the relationship between the object and the model, but I'm having a lot of trouble figuring it out from documentation. Can someone help me get my fragment working the way I want it to?

Your problem isn't specific to models or almost anything TornadoFX-related. The way you've written it only checks for the color once upon creation. You need to use properties or bindings to listen to property changes:

class Test : Fragment() {
    val modelAchieved = SimpleBooleanProperty(true) // pretend this is model.achieved
    val achievedColor = modelAchieved.objectBinding { isAchieved ->
        if (isAchieved == true) Color.RED
        else Color.GREEN
    }

    override val root = vbox {
        togglebutton("Toggle") {
            selectedProperty().bindBidirectional(modelAchieved)
        }
        rectangle(width = 50, height = 50) {
            stroke = Color.BLACK
            fillProperty().bind(achievedColor)
        }
    }
}

I would also bidirectionally bind the item properties of the viewmodel and fragment together so they stay in sync. Or just use a regular fragment, and reference the model's item property by itself.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM