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

ItemsControl与数据源不一致:WPF DataGrid操作崩溃问题

解决WPF DataGrid集合操作时的ItemsControl数据源不一致异常

这个问题我之前也碰到过,典型的WPF集合绑定没做好变更通知导致的!咱们一步步来拆解和解决:

问题根源

你抛出的System.InvalidOperationException异常,核心原因是你的数据源没有实现INotifyCollectionChanged接口。WPF的ItemsControl(包括DataGrid)依赖这个接口来同步UI和数据源的状态:当集合增删元素时,需要通知UI更新。如果用普通的ICollection或者List,修改集合后UI不会收到通知,多次操作后UI的内部状态和实际数据源就会脱节,最终触发校验崩溃。

具体解决方案

1. 把ViewModel的集合换成ObservableCollection

ObservableCollection是WPF专门设计的集合类型,自动实现了INotifyCollectionChanged和INotifyPropertyChanged,能实时通知UI集合变化。

修改ViewModel里的集合定义:

// 原来的ICollection替换成ObservableCollection
private ObservableCollection<RentalItem> _allItems;
private ObservableCollection<RentalItem> _addedItems;

public ObservableCollection<RentalItem> AllItems
{
    get => _allItems;
    set => SetProperty(ref _allItems, value); // 假设你的ViewModelBase有SetProperty实现
}

public ObservableCollection<RentalItem> AddedItems
{
    get => _addedItems;
    set => SetProperty(ref _addedItems, value);
}

2. 加载数据时初始化ObservableCollection

从数据库加载数据后,要把结果转换成ObservableCollection,而不是直接用数据库返回的普通集合:

// 示例:从服务获取数据后初始化
var availableItems = itemService.GetAvailableRentalItems(); // 假设返回IEnumerable<RentalItem>
AllItems = new ObservableCollection<RentalItem>(availableItems);
AddedItems = new ObservableCollection<RentalItem>();

3. 修正Add/Remove命令的实现

确保命令里直接操作ObservableCollection的实例,这样每一次增删都会自动通知UI:

// AddItemCommand示例(用RelayCommand,假设你用的是MVVM Light或类似框架)
public ICommand AddItemCommand => new RelayCommand<int>(itemId =>
{
    var targetItem = AllItems.FirstOrDefault(item => item.Id == itemId);
    if (targetItem != null)
    {
        AllItems.Remove(targetItem);
        AddedItems.Add(targetItem);
    }
});

// RemoveItemCommand示例
public ICommand RemoveItemCommand => new RelayCommand<int>(itemId =>
{
    var targetItem = AddedItems.FirstOrDefault(item => item.Id == itemId);
    if (targetItem != null)
    {
        AddedItems.Remove(targetItem);
        AllItems.Add(targetItem);
    }
});

4. 移除View里重复的Click事件

你的Add按钮同时绑定了Command和Click="OnAddButton",这会导致操作被触发两次,加剧状态不一致的问题。直接删掉Click事件,只用Command:

<!-- 修改前 -->
<Button Content="Add" Command="{Binding DataContext.AddItemCommand, RelativeSource={RelativeSource AncestorType=UserControl}}" CommandParameter="{Binding Id}" Click="OnAddButton" >

<!-- 修改后 -->
<Button Content="Add" Command="{Binding DataContext.AddItemCommand, RelativeSource={RelativeSource AncestorType=UserControl}}" CommandParameter="{Binding Id}" >

为什么这样能解决问题?

当你用ObservableCollection时,每次调用Add/Remove都会触发CollectionChanged事件,WPF的DataGrid会监听这个事件,实时更新UI的Items集合,保证UI和数据源的状态完全同步,就不会再出现“累计计数与实际计数不符”的异常了。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.27 07:30:03