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

WPF MVVM中DataGrid绑定ObservableCollection后仍为空的问题

WPF DataGrid绑定ObservableCollection后更新数据不显示的问题解决

问题场景

在WPF DataGrid绑定ObservableCollection的场景中,构造函数初始化的集合元素能正常显示,但通过事件触发更新时(重新赋值集合),DataGrid始终显示0条数据。已确认更新方法OnReportSyncCompletedMessage被调用,且集合已填充数据,但绑定未生效。

核心原因

ObservableCollection的自动更新通知仅针对集合内部元素的增、删、改操作(触发CollectionChanged事件)。如果直接重新实例化ObservableCollection并赋值给ViewModel属性,由于属性未触发PropertyChanged事件,WPF绑定系统无法感知到集合引用的变化,仍会使用初始绑定的空集合实例,导致新数据无法显示。

解决方案

方案1:复用原集合,清空后添加新元素

不替换集合对象,而是清空原集合的内容,再批量添加新数据。这种方式利用ObservableCollection自身的CollectionChanged通知机制,无需修改属性结构。

修改OnReportSyncCompletedMessage方法:

private void OnReportSyncCompletedMessage(ReportSyncCompletedMessage obj)
{
    // 更新成功报告集合
    SuccessReports.Clear();
    foreach (var report in obj.ReportSyncStatusUpload.SuccessReports)
    {
        SuccessReports.Add(report);
    }

    // 更新失败报告集合
    FailedReports.Clear();
    foreach (var report in obj.ReportSyncStatusUpload.FailedReports)
    {
        FailedReports.Add(report);
    }
}

方案2:修改属性为触发PropertyChanged的通知属性

将ViewModel的集合属性改为支持INotifyPropertyChanged的通知属性,赋值时触发属性变更通知,让WPF绑定系统感知到集合引用的变化。

步骤1:重构ViewModel属性

假设你的ViewModelBase已实现INotifyPropertyChanged接口,且提供了Set<T>方法用于触发通知:

public class ReportSyncerStatusViewModel : ViewModelBase
{
    private ObservableCollection<ReportEntity> _successReports;
    public ObservableCollection<ReportEntity> SuccessReports
    {
        get => _successReports;
        private set => Set(ref _successReports, value);
    }

    private ObservableCollection<ReportEntity> _failedReports;
    public ObservableCollection<ReportEntity> FailedReports
    {
        get => _failedReports;
        private set => Set(ref _failedReports, value);
    }        

    public ReportSyncerStatusViewModel()
    {
        _successReports = new ObservableCollection<ReportEntity>();
        _failedReports = new ObservableCollection<ReportEntity>();
        Messenger.Default.Register<ReportSyncCompletedMessage>(this, OnReportSyncCompletedMessage);    
    }

    private void OnReportSyncCompletedMessage(ReportSyncCompletedMessage obj)
    {
        SuccessReports = new ObservableCollection<ReportEntity>(obj.ReportSyncStatusUpload.SuccessReports);
        FailedReports = new ObservableCollection<ReportEntity>(obj.ReportSyncStatusUpload.FailedReports);
    }
}

如果ViewModelBase没有封装Set<T>方法,可手动触发PropertyChanged:

private ObservableCollection<ReportEntity> _successReports;
public ObservableCollection<ReportEntity> SuccessReports
{
    get => _successReports;
    private set
    {
        if (_successReports != value)
        {
            _successReports = value;
            OnPropertyChanged(nameof(SuccessReports));
        }
    }
}

// FailedReports属性同理

步骤2:确保ViewModelBase实现INotifyPropertyChanged

如果ViewModelBase未实现该接口,需补充基础实现:

public class ViewModelBase : INotifyPropertyChanged
{
    public event PropertyChangedEventHandler PropertyChanged;

    protected virtual void OnPropertyChanged(string propertyName)
    {
        PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
    }

    // 可选:封装Set<T>方法简化代码
    protected bool Set<T>(ref T field, T value, [CallerMemberName] string propertyName = null)
    {
        if (EqualityComparer<T>.Default.Equals(field, value))
            return false;

        field = value;
        OnPropertyChanged(propertyName);
        return true;
    }
}

方案选择

  • 方案1适合不需要频繁替换整个集合的场景,无需修改属性结构,直接利用集合自身的通知机制。
  • 方案2适合需要频繁替换集合的场景,代码更简洁,逻辑更清晰。

内容的提问来源于stack exchange,提问作者Vlado Pandžić

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.25 16:04:53