WPF MVVM中点击按钮后DataGrid新增行无法即时显示的解决方法
WPF MVVM中DataGrid点击按钮无法即时新增行的问题修复
问题描述
在C# WPF MVVM架构下,点击DataGrid行内的「Add Row」按钮后,新增的行无法即时显示,只有点击其他控件(如TextBox)时才会出现。
原代码
NewDocumentView.xaml
<DataGrid x:Name="DataGrid" AutoGenerateColumns="False" HorizontalAlignment="Left" VerticalAlignment="Top" Grid.Row="1" Margin="20,350,0,0" ItemsSource="{Binding Items}"> <DataGrid.Columns> <DataGridTextColumn Header="Description" Binding="{Binding Description}" Width="500"/> <DataGridTextColumn Header="Unit" Binding="{Binding Unit}" Width="100"/> <DataGridTextColumn Header="Price" Binding="{Binding Price}" Width="100"/> <DataGridTextColumn Header="Total" Binding="{Binding Total}" Width="100"/> <DataGridTemplateColumn Header="Actions"> <DataGridTemplateColumn.CellTemplate> <DataTemplate> <Button Content="Add Row" Command="{Binding AddItemCommand}" Width="100"/> </DataTemplate> </DataGridTemplateColumn.CellTemplate> </DataGridTemplateColumn> </DataGrid.Columns> </DataGrid>
NewDocumentViewModel.cs
namespace App.MVVM.ViewModel { internal class NewDocumentViewModel : ObservableObject { public ObservableCollection<Item> Items { get; set; } = new ObservableCollection<Item>(); public RelayCommand AddItemCommand { get; set; } public NewDocumentViewModel() { Items = new ObservableCollection<Item>(); AddItemCommand = new RelayCommand(o => { AddNewItem(); }); } private void AddNewItem() { Items.Add(new Item()); } } }
NewDocumentView.xaml.cs
namespace App.MVVM.View { public partial class NewDocumentView : UserControl { public NewDocumentView() { InitializeComponent(); DataContext = new NewDocumentViewModel(); } } }
Item.cs
namespace App.MVVM.Model { class Item : ObservableObject { private string _description; public string Description { get { return _description; } set { if (_description != value) { _description = value; OnPropertyChanged(nameof(Description)); } } } private string _unit; public string Unit { get { return _unit; } set { if (_unit != value) { _unit = value; OnPropertyChanged(nameof(Unit)); } } } private int _price; public int Price { get { return _price; } set { if (_price != value) { _price = value; OnPropertyChanged(nameof(Price)); } } } private int _total; public int Total { get { return _total; } set { if (_total != value) { _total = value; OnPropertyChanged(nameof(Total)); } } } } }
ObservableObject.cs
namespace App.Core { internal class ObservableObject : INotifyPropertyChanged { public event PropertyChangedEventHandler? PropertyChanged; protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null) { PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName)); } } }
RelayCommand.cs
namespace App.Core { internal class RelayCommand : ICommand { private readonly Action<object> execute; private readonly Func<object, bool> canExecute; public RelayCommand(Action<object> execute, Func<object, bool> canExecute = null) { this.execute = execute; this.canExecute = canExecute; } public event EventHandler CanExecuteChanged { add => CommandManager.RequerySuggested += value; remove => CommandManager.RequerySuggested -= value; } public bool CanExecute(object parameter) { return canExecute == null || canExecute(parameter); } public void Execute(object parameter) { execute(parameter); } } }
问题根源
核心错误是DataGrid单元格内Button的命令绑定目标错误:
DataGrid的CellTemplate中,控件的默认DataContext是当前行对应的Item实例,而AddItemCommand是定义在NewDocumentViewModel中的。直接使用{Binding AddItemCommand}会导致绑定找不到目标命令,按钮点击后实际没有执行ViewModel中的新增逻辑。后续点击其他控件时,UI触发强制刷新,才会显示出可能因其他操作误添加的行。
修复方案
修改Button的Command绑定,通过RelativeSource向上查找DataGrid的DataContext(即ViewModel实例),从而正确绑定到AddItemCommand。
修改后的Button代码:
<Button Content="Add Row" Command="{Binding DataContext.AddItemCommand, RelativeSource={RelativeSource AncestorType={x:Type DataGrid}}}" Width="100"/>
验证说明
ObservableCollection<Item>本身支持集合变更通知,只要正确调用Items.Add(),会自动通知DataGrid更新UI,实现即时显示新增行。- 其他代码(
Item的属性变更通知、RelayCommand实现、ViewModel初始化)均符合MVVM规范,无需修改。
内容的提问来源于stack exchange,提问作者Mauzuk
相关产品推荐
相关产品推荐

