You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何从异步方法更新GTK ListBox?问题排查与实现

解决GTK ListModel items_changed信号不触发的问题

我仔细看了你的代码,发现几个关键问题导致items_changed信号没触发,进而ListBox无法更新,咱们一步步来修正:

1. 核心问题:被覆盖的集合引用

在AsyncFileContext的构造函数里,你先把传入的vcards赋值给_vCards,紧接着又用新创建的集合覆盖了它:

public AsyncFileContext(IObservableSet<IVCard> vcards, string path){
    this._vCards = vcards;
    this._vCards = IObservableSet.wrap_set<IVCard>(new Gee.HashSet<IVCard>()); // 这里直接覆盖了传入的集合!
    // ... 其他代码
}

这就导致:你在read_file_async里往_vCards添加元素时,操作的是一个全新的集合,而VCardListModel监听的是最初传入的那个集合——两者完全没关系,自然收不到item_added信号,更不会触发items_changed。

修正方法:去掉覆盖的那行代码,保留传入的集合引用:

public AsyncFileContext(IObservableSet<IVCard> vcards, string path){
    this._vCards = vcards;
    // 删掉 this._vCards = IObservableSet.wrap_set<...>(); 这一行
    this.file = File.new_for_path(path);
    // ... 其他代码保持不变
}

2. vcard_buffer的逻辑错误

在read_file_async里,你添加元素后立刻从vcard_buffer移除所有已加入_vCards的元素,这会导致vcard_buffer刚添加的元素被清空,但逻辑上你应该是想在添加后清空缓冲区:

Idle.add(() => {
    _vCards.add_all(vcard_buffer);
    vcard_buffer.remove_all(_vCards); // 这里错误,应该是清空缓冲区
    return false;
});

修正方法:用clear()替代remove_all(_vCards):

Idle.add(() => {
    _vCards.add_all(vcard_buffer);
    vcard_buffer.clear(); // 清空缓冲区,准备下一批数据
    return false;
});

3. 优化VCardListModel的信号触发逻辑

在VCardListModel的item_added回调里,你用index_of查找位置,其实可以直接用集合的当前长度(因为是添加到末尾),既高效又避免可能的索引查找错误:

this.vcard_collection.item_added.connect((vcard) => {
    int pos = vcard_list.size; // 新元素的位置是当前集合长度(add到末尾后会自动+1)
    vcard_list.add(vcard);
    items_changed((uint)pos, 0, 1);
});

另外,get_object方法是冗余的,ListModel的标准接口是get_item,可以删掉这个方法,避免混淆。

4. 简化异步操作的恢复逻辑

你在read_file_async里用Idle.add(read_file_async.callback)来恢复异步执行,其实不需要这么做——yield本身就会暂停并在合适时机恢复执行,直接去掉这行代码即可:

if(factory.vcard_ready){
    message("creating...");
    this.vcard_buffer.add(factory.create());
    vcards_added++;
    message("Yielding...");
    Idle.add(() => {
        _vCards.add_all(vcard_buffer);
        vcard_buffer.clear();
        return false;
    });
    yield; // 这里会自动恢复执行,不需要额外回调
    message("Resuming");
}

验证信号触发

修正后,你在ContactList里绑定的list_model.items_changed信号应该能正常触发,ListBox也会自动更新列表项了。如果还是有问题,可以检查IObservableCollection的item_added信号是否正确发射——因为VCardListModel完全依赖这个信号来触发items_changed。

内容的提问来源于stack exchange,提问作者rasmus91

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.14 08:15:22