Asynchronous 树视图的异步加载

Asynchronous 树视图的异步加载,asynchronous,kotlin,tornadofx,Asynchronous,Kotlin,Tornadofx,嘿,我对treeview异步加载数据非常陌生。我正在从rest端点加载类别,我想在那里显示 似乎没有直接的数据绑定到孩子们 使用“bindChildren”时,我可以提供可观察列表,但我必须将它们转换为节点的。这样一来,填充块就有点过时了 推荐的方法是什么?我找不到关于这个的任何东西 // Category interface Category<T : Category<T>> { val id: String val name: String val sub

嘿,我对treeview异步加载数据非常陌生。我正在从rest端点加载类别,我想在那里显示

似乎没有直接的数据绑定到孩子们

使用“bindChildren”时,我可以提供可观察列表,但我必须将它们转换为节点的。这样一来,填充块就有点过时了

推荐的方法是什么?我找不到关于这个的任何东西

// Category
interface Category<T : Category<T>> {
  val id: String
  val name: String
  val subcategories: List<T>?
}


//default category:
class DefaultCategory(override val name: String) : Category<DefaultCategory> {
  override val id: String = "default"
  override val subcategories: List<DefaultCategory>? = null
}
//ViewModel
class CategoryViewModel : ViewModel() {
  val sourceProperty = SimpleListProperty<Category<*>>()
  fun loadData() {
    // load items for treeview into 'newItems'
    sourceProperty.value = newItems
  }
}

// TreeViewFactoryMethod
private fun createTreeView(
  listProperty: SimpleListProperty<Category<*>>
): TreeView<Category<*>> {
  return treeview {
    root = TreeItem(DefaultCategory("Categories"))
    isShowRoot = false
    root.isExpanded = true
    root.children.forEach { it.isExpanded = true }
    cellFormat { text = it.name }
    populate { parent ->
      when (parent) {
        root -> listProperty.value
        else -> parent.value.subcategories
      }
    }
  }
}
//类别
接口类别{
valid:String
val名称:String
val子类别:列表?
}
//默认类别:
类DefaultCategory(覆盖值名称:字符串):类别{
覆盖val id:String=“默认”
覆盖val子类别:列表?=null
}
//视图模型
类CategoryViewModel:ViewModel(){
val sourceProperty=SimpleListProperty()
fun loadData(){
//将treeview的项目加载到“newItems”中
sourceProperty.value=newItems
}
}
//TreeviewFactory方法
私人娱乐createTreeView(
listProperty:SimpleListProperty
):TreeView{
返回树视图{
root=TreeItem(默认类别(“类别”))
isShowRoot=false
root.isExpanded=true
root.children.forEach{it.isExpanded=true}
cellFormat{text=it.name}
填充{parent->
何时(家长){
root->listProperty.value
else->parent.value.subcategories
}
}
}
}

假设在单击按钮时调用
viewmodel.loadData()
,我希望树视图在出现新数据时立即更新。(如果我能找到一种绑定方法的话)

我以前从未在TornadFX中使用过
bindChildren
,而您对异步的使用与我认为您的主要问题不太相关。诚然,这个问题一开始让我有些困惑,但我猜你只是想知道为什么列表没有出现在你的
树视图中?我已经制作了一个测试示例,并对其进行了更改以使其正常工作

// Category
interface Category<T : Category<T>> {
    val id: String
    val name: String
    val subcategories: List<T>?
}

//default category:
class DefaultCategory(override val name: String) : Category<DefaultCategory> {
    override val id: String = "default"
    override val subcategories: List<DefaultCategory>? = null
}
//Just a dummy category
class ChildCategory(override val name: String) : Category<ChildCategory> {
    override val id = name
    override val subcategories: List<ChildCategory>? = null
}

//ViewModel
class CategoryViewModel : ViewModel() {
    //filled with dummy data
    val sourceProperty = SimpleListProperty<Category<*>>(listOf(
            ChildCategory("Categorya"),
            ChildCategory("Categoryb"),
            ChildCategory("Categoryc"),
            ChildCategory("Categoryd")
    ).asObservable())

    fun loadData() {
        sourceProperty.asyncItems {
            //items grabbed somehow
            listOf(
                    ChildCategory("Category1"),
                    ChildCategory("Category2"),
                    ChildCategory("Category3"),
                    ChildCategory("Category4")
            ).asObservable()
        }
    }
}


class TestView : View() {
    val model: CategoryViewModel by inject()

    override val root = vbox(10) {
        button("Refresh Items").action {
            model.loadData()
        }
        add(createTreeView(model.sourceProperty))
    }

    // TreeViewFactoryMethod
    private fun createTreeView(
            listProperty: SimpleListProperty<Category<*>>
    ): TreeView<Category<*>> {
        return treeview {
            root = TreeItem(DefaultCategory("Categories"))
            isShowRoot = false
            root.isExpanded = true
            root.children.forEach { it.isExpanded = true }
            cellFormat { text = it.name }
            populate { parent ->
                when (parent) {
                    root -> listProperty
                    else -> parent.value.subcategories
                }
            }
        }
    }
}
//类别
接口类别{
valid:String
val名称:String
val子类别:列表?
}
//默认类别:
类DefaultCategory(覆盖值名称:字符串):类别{
覆盖val id:String=“默认”
覆盖val子类别:列表?=null
}
//只是一个虚拟类别
类ChildCategory(覆盖值名称:字符串):类别{
覆盖值id=name
覆盖val子类别:列表?=null
}
//视图模型
类CategoryViewModel:ViewModel(){
//填充了虚拟数据
val sourceProperty=SimpleListProperty(列表属性(
儿童类别(“类别”),
儿童类别(“类别B”),
儿童类别(“类别”),
儿童类别(“分类”)
).asObservable())
fun loadData(){
sourceProperty.asyncItems{
//不知怎么被抢走的东西
列表(
儿童类别(“类别1”),
儿童类别(“类别2”),
儿童类别(“类别3”),
儿童类别(“类别4”)
).asObservable()
}
}
}
类TestView:View(){
val模型:CategoryViewModel by inject()
覆盖val root=vbox(10){
按钮(“刷新项”)。操作{
model.loadData()
}
添加(createTreeView(model.sourceProperty))
}
//TreeviewFactory方法
私人娱乐createTreeView(
listProperty:SimpleListProperty
):TreeView{
返回树视图{
root=TreeItem(默认类别(“类别”))
isShowRoot=false
root.isExpanded=true
root.children.forEach{it.isExpanded=true}
cellFormat{text=it.name}
填充{parent->
何时(家长){
根->列表属性
else->parent.value.subcategories
}
}
}
}
}
有两个重要的区别是重要的

1。更相关的区别是,在填充块中,使用
root->listProperty
而不是
root.listProperty.value
。这将显示您的列表。原因是
SimpleListProperty
不是列表,它包含一个列表。因此,是的,传入一个普通列表是完全有效的(就像传入list属性的值一样)。但现在这意味着树视图没有监听您的属性,只监听您传入的列表。考虑到这一点,我会考虑是否也实现了类别的子类别列表


2.其次,请注意
ViewModel
中使用的
asyncItems
。这将异步执行任何任务,然后将项目设置为成功时列出。您甚至可以向其添加
fail
cancel
块。我建议使用此选项,因为不应在UI线程上执行长时间/密集型操作。

sourceProperty.asyncItems
是缺少的链接。非常感谢。