WPF DataGrid绑定SelectedItem后ViewModel属性更新无法同步至DataGrid
问题:WPF中VM属性更新无法同步至DataGrid
在WPF UserControl中,存在一个只读DataGrid绑定至ViewModel(VM),其SelectedItem绑定到VM的属性。同时有两个TextBox:一个绑定SelectedItem的属性,修改后可同步至DataGrid;另一个绑定VM的属性,修改后无法同步到DataGrid。
相关XAML代码
<UserControl x:Class="PhoneAssistant.WPF.Features.ServiceRequests.ServiceRequestsMainView" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:local="clr-namespace:PhoneAssistant.WPF.Features.ServiceRequests" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" d:DataContext="{d:DesignInstance Type=local:ServiceRequestsMainViewModel}" d:DesignHeight="450" d:DesignWidth="800" mc:Ignorable="d"> <Grid> <Grid.RowDefinitions> <RowDefinition Height="Auto" /> <RowDefinition Height="*" /> </Grid.RowDefinitions> <Grid Grid.Row="0" Margin="16,20,0,15" d:Background="LightCoral"> <Grid.ColumnDefinitions> <ColumnDefinition Width="auto" /> <ColumnDefinition Width="auto" /> </Grid.ColumnDefinitions> <TextBox Grid.Column="0" Margin="0,0,5,0" Text="{Binding SelectedSR.BoundToSelected}" /> <TextBox Grid.Column="1" Margin="0,0,5,0" Text="{Binding VmProperty}" /> </Grid> <DataGrid Grid.Row="1" AutoGenerateColumns="False" IsReadOnly="true" ItemsSource="{Binding ServiceRequests}" SelectedItem="{Binding SelectedSR}" SelectionMode="Single" SelectionUnit="FullRow"> <DataGrid.Columns> <DataGridTextColumn Width="auto" Binding="{Binding BoundToSelected}" Header="BoundToSelected" /> <DataGridTextColumn Width="auto" Binding="{Binding BoundToVMProperty}" Header="BoundToVMProperty" /> </DataGrid.Columns> </DataGrid> </Grid> </UserControl>
相关C#代码
using System.Collections.ObjectModel; using CommunityToolkit.Mvvm.ComponentModel; namespace PhoneAssistant.WPF.Features.ServiceRequests; public sealed partial class ServiceRequestsMainViewModel : ObservableObject, IServiceRequestsMainViewModel { public ObservableCollection<ServiceRequest> ServiceRequests { get; } = new(); [ObservableProperty] private ServiceRequest _selectedSR; partial void OnSelectedSRChanged(ServiceRequest value) { VmProperty = value.BoundToVMProperty; } [ObservableProperty] // Neither of these notifies update the datagrid [NotifyPropertyChangedFor(nameof(ServiceRequests))] [NotifyPropertyChangedFor(nameof(SelectedSR))] private string _vmProperty; partial void OnVmPropertyChanged(string value) { SelectedSR.BoundToVMProperty = value; } public Task LoadAsync() { ServiceRequests.Add(new ServiceRequest() { Id = 1, BoundToSelected = "SomeValue1", BoundToVMProperty = "AnotherValee1"}); ServiceRequests.Add(new ServiceRequest() { Id = 2, BoundToSelected = "SomeValue2", BoundToVMProperty = "AnotherValee2" }); ServiceRequests.Add(new ServiceRequest() { Id = 3, BoundToSelected = "SomeValue3", BoundToVMProperty = "AnotherValee3" }); return Task.CompletedTask; } } public sealed class ServiceRequest { public int Id { get; init; } public string BoundToSelected { get; set; } public string BoundToVMProperty { get; set; } }
解决方案
核心问题在于ServiceRequest类的属性没有实现属性更改通知,导致DataGrid无法感知到属性值的变化。WPF数据绑定依赖INotifyPropertyChanged接口来更新UI,当属性值变化时需要触发PropertyChanged事件。
步骤1:修改ServiceRequest类,实现属性更改通知
借助CommunityToolkit.Mvvm的ObservableObject基类和[ObservableProperty]特性,可以快速实现通知机制:
using CommunityToolkit.Mvvm.ComponentModel; namespace PhoneAssistant.WPF.Features.ServiceRequests; public sealed partial class ServiceRequest : ObservableObject { public int Id { get; init; } [ObservableProperty] private string _boundToSelected; [ObservableProperty] private string _boundToVMProperty; }
步骤2:调整ViewModel中的绑定逻辑(可选优化)
ViewModel中原来的[NotifyPropertyChangedFor]注解可以移除,因为它们对解决当前问题没有作用。修改后的ViewModel代码如下:
using System.Collections.ObjectModel; using CommunityToolkit.Mvvm.ComponentModel; namespace PhoneAssistant.WPF.Features.ServiceRequests; public sealed partial class ServiceRequestsMainViewModel : ObservableObject, IServiceRequestsMainViewModel { public ObservableCollection<ServiceRequest> ServiceRequests { get; } = new(); [ObservableProperty] private ServiceRequest _selectedSR; partial void OnSelectedSRChanged(ServiceRequest value) { VmProperty = value.BoundToVMProperty; } [ObservableProperty] private string _vmProperty; partial void OnVmPropertyChanged(string value) { SelectedSR?.BoundToVMProperty = value; } public Task LoadAsync() { ServiceRequests.Add(new ServiceRequest() { Id = 1, BoundToSelected = "SomeValue1", BoundToVMProperty = "AnotherValee1"}); ServiceRequests.Add(new ServiceRequest() { Id = 2, BoundToSelected = "SomeValue2", BoundToVMProperty = "AnotherValee2" }); ServiceRequests.Add(new ServiceRequest() { Id = 3, BoundToSelected = "SomeValue3", BoundToVMProperty = "AnotherValee3" }); return Task.CompletedTask; } }
原理说明
- 当
VmProperty修改时,OnVmPropertyChanged会更新SelectedSR.BoundToVMProperty的值。 - 由于
ServiceRequest现在继承了ObservableObject,BoundToVMProperty属性变化时会自动触发PropertyChanged事件。 - DataGrid的列绑定会监听该事件,从而自动更新对应单元格的显示内容。
内容的提问来源于stack exchange,提问作者JCL
相关产品推荐
相关产品推荐

