Avalonia DataGrid跨列更新属性时单元格值不同步问题
问题场景
使用WPF DataGrid控件实现两列绑定到同一EntryLog模型的Date属性,列定义如下XAML:
<DataGrid Margin="10" BorderBrush="Black" BorderThickness="1" Grid.Row="1" Grid.ColumnSpan="3" Items="{Binding Logs}" AutoGenerateColumns="False" > <DataGrid.Columns> <DataGridTextColumn Header="Temp Date" Binding="{Binding Date,Mode=TwoWay}" > </DataGridTextColumn> <DataGridTemplateColumn Header="Calendar Column" CellTemplate="{Binding TestTemplate}" CellEditingTemplate="{Binding EditingTemplate}" > </DataGridTemplateColumn> </DataGrid.Columns> </DataGrid>
ViewModel中通过代码动态创建单元格模板,普通显示状态的CellTemplate定义:
// Cell Data Template TestTemplate = new FuncDataTemplate<EntryLog>((value, namescope) => new TextBlock { [!TextBlock.TextProperty] = new Binding("Date",BindingMode.TwoWay), });
编辑状态的CellEditingTemplate定义:
// Cell Editing Data Template EditingTemplate = new FuncDataTemplate<EntryLog>((value, namescope) => { var grid = new Grid(); var tb = new TextBlock { [!TextBlock.TextProperty] = new Binding("Date", BindingMode.TwoWay), }; grid.Children.Add(tb); var calendar = new Calendar(); calendar.DisplayDate = value.Date; calendar.SelectedDate = value.Date; Popup popup = new Popup(); popup.Child = calendar; popup.IsOpen = true; calendar.SelectedDatesChanged += (s, e) => { value.Date = calendar.SelectedDate.Value.Date; //tb.Text = value.Date.ToString(); }; grid.Children.Add(popup); return grid; });
编辑态UI效果:
核心故障:任意一列修改绑定的Date属性值时,另一列的单元格值不会同步更新。
已知配置:DataGrid的ItemsSource绑定EntryLog类型的ObservableCollection集合,EntryLog已实现INotifyPropertyChanged接口,模型代码如下:
public class EntryLog : INotifyPropertyChanged { private DateTime _date; public DateTime Date { get => _date; set { if (_date != value) PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(Date))); _date = value; } } public string Description { get; set; } public double Hours { get; set; } public event PropertyChangedEventHandler? PropertyChanged; }
根因定位
故障由3处实现错误共同导致:
- EntryLog的属性通知逻辑顺序错误:当前
Date属性的set块中,先触发PropertyChanged事件,再给后备字段_date赋值。事件触发时UI读取到的还是旧值,绑定系统拿到旧值不会刷新显示。 - 编辑模板内Calendar控件未正确绑定到Date属性:编辑态的Calendar控件直接通过代码赋值
DisplayDate和SelectedDate,没有建立和Date属性的双向绑定,选择日期时直接手动给value.Date赋值,绕过了WPF的绑定更新流转逻辑,加上DataGrid行编辑状态下默认会缓存编辑值,不会主动刷新其他列的显示。 - XAML中DataGrid的数据源属性拼写错误:原XAML写的是
Items="{Binding Logs}",DataGrid接收列表数据源的属性是ItemsSource,拼写错误会导致绑定无法正常工作,集合和属性的变更通知无法被DataGrid正确接收。
修复方案
按以下步骤修改即可解决两列值不同步的问题:
- 修正EntryLog的Date属性通知顺序,先更新字段值再触发变更事件
public DateTime Date { get => _date; set { if (_date != value) { _date = value; // 先更新字段存储值 PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(Date))); // 再发送变更通知 } } }
- 修正XAML中DataGrid的数据源绑定属性名,把
Items改为ItemsSource - 修改编辑模板中Calendar的实现,建立和Date属性的双向绑定,移除手动赋值的事件逻辑:
EditingTemplate = new FuncDataTemplate<EntryLog>((value, namescope) => { var grid = new Grid(); var tb = new TextBlock { [!TextBlock.TextProperty] = new Binding("Date", BindingMode.TwoWay), }; grid.Children.Add(tb); var calendar = new Calendar(); // 为Calendar的SelectedDate建立双向绑定,替换原有手动赋值逻辑 calendar.SetBinding(Calendar.SelectedDateProperty, new Binding("Date") { Mode = BindingMode.TwoWay, UpdateSourceTrigger = UpdateSourceTrigger.PropertyChanged }); Popup popup = new Popup(); popup.Child = calendar; popup.IsOpen = true; // 移除手动给value.Date赋值的事件处理,绑定机制会自动完成值流转同步 grid.Children.Add(popup); return grid; });
内容的提问来源于stack exchange,提问作者Jeremy Loh
相关产品推荐
相关产品推荐

