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

如何基于ObservableCollection<T>状态更新Progress进度值?

解决嵌套ObservableCollection下Progress不更新的问题

问题根源

Progress值不更新的核心原因:

  • Progress作为计算属性,未在底层数据变化时触发PropertyChanged通知,UI无法感知值的变更。
  • 未监听外层ObservableCollection<T>的集合增删操作。
  • 未监听每个T对象内部ObservableCollection<U>的集合增删操作。
  • U类的IsCompleted属性未公开,也未实现属性变更通知。

修复方案

1. 修复U类的属性通知逻辑

确保IsCompleted为公开属性,并触发属性变更通知:

class U : ObservableObjectBase
{
    private bool _isCompleted;
    public bool IsCompleted
    {
        get => _isCompleted;
        set => SetProperty(ref _isCompleted, value);
    }
}

2. 完善ViewModel的多层监听逻辑

修改ViewModel,添加集合和属性变更的全链路监听,确保任何底层数据变化都能触发Progress更新:

class TestViewModel : ObservableObjectBase
{
    private ObservableCollection<T> _items;
    public ObservableCollection<T> Items
    {
        get => _items;
        set
        {
            if (_items != value)
            {
                // 移除旧集合的所有监听
                if (_items != null)
                {
                    _items.CollectionChanged -= Items_CollectionChanged;
                    UnsubscribeFromAllNestedItems(_items);
                }
                _items = value;
                // 为新集合添加监听
                if (_items != null)
                {
                    _items.CollectionChanged += Items_CollectionChanged;
                    SubscribeToAllNestedItems(_items);
                }
                OnPropertyChanged(nameof(Items));
                OnPropertyChanged(nameof(Progress));
            }
        }
    }

    public double Progress
    {
        get
        {
            if (Items == null || Items.Sum(e => e.NestedItems.Count) == 0)
                return 0;

            var completedCount = Items.SelectMany(e => e.NestedItems).Count(u => u.IsCompleted);
            var totalCount = Items.Sum(e => e.NestedItems.Count);
            return (double)completedCount / totalCount;
        }
    }

    void Init()
    {
        // 加载数据后赋值Items,自动触发监听初始化
        Items = LoadData();
    }

    // 监听外层Items集合的增删
    private void Items_CollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
    {
        if (e.NewItems != null)
        {
            foreach (T item in e.NewItems)
            {
                SubscribeToNestedItems(item);
            }
        }
        if (e.OldItems != null)
        {
            foreach (T item in e.OldItems)
            {
                UnsubscribeFromNestedItems(item);
            }
        }
        OnPropertyChanged(nameof(Progress));
    }

    // 为单个T对象的NestedItems添加监听
    private void SubscribeToNestedItems(T item)
    {
        item.NestedItems.CollectionChanged += NestedItems_CollectionChanged;
        // 为已存在的U对象订阅属性变更
        foreach (U u in item.NestedItems)
        {
            u.PropertyChanged += U_PropertyChanged;
        }
    }

    // 移除单个T对象的NestedItems监听
    private void UnsubscribeFromNestedItems(T item)
    {
        item.NestedItems.CollectionChanged -= NestedItems_CollectionChanged;
        foreach (U u in item.NestedItems)
        {
            u.PropertyChanged -= U_PropertyChanged;
        }
    }

    // 监听NestedItems集合的增删
    private void NestedItems_CollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
    {
        if (e.NewItems != null)
        {
            foreach (U u in e.NewItems)
            {
                u.PropertyChanged += U_PropertyChanged;
            }
        }
        if (e.OldItems != null)
        {
            foreach (U u in e.OldItems)
            {
                u.PropertyChanged -= U_PropertyChanged;
            }
        }
        OnPropertyChanged(nameof(Progress));
    }

    // 监听U对象的IsCompleted属性变化
    private void U_PropertyChanged(object sender, PropertyChangedEventArgs e)
    {
        if (e.PropertyName == nameof(U.IsCompleted))
        {
            OnPropertyChanged(nameof(Progress));
        }
    }

    // 批量订阅所有T对象的NestedItems
    private void SubscribeToAllNestedItems(ObservableCollection<T> items)
    {
        foreach (T item in items)
        {
            SubscribeToNestedItems(item);
        }
    }

    // 批量取消所有T对象的NestedItems订阅
    private void UnsubscribeFromAllNestedItems(ObservableCollection<T> items)
    {
        foreach (T item in items)
        {
            UnsubscribeFromNestedItems(item);
        }
    }
}

3. 优化XAML绑定(可选)

显式指定绑定模式确保单向更新:

<ProgressBar Progress="{Binding Progress, Mode=OneWay}" />

效果说明

  • 外层Items集合增删T对象时,自动处理内部NestedItems的监听逻辑。
  • NestedItems集合增删U对象时,自动订阅/取消U的属性变更监听。
  • U的IsCompleted属性变化时,立即触发Progress的PropertyChanged通知,UI自动更新进度值。

内容的提问来源于stack exchange,提问作者Zoltán

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.28 18:41:06