DataGrid中Checkbox绑定数据后,如何按正确顺序触发事件?
问题
在WPF的DataGrid中,尝试在Checkbox值变化时立即执行计算,但遇到时序问题:点击复选框时,计算函数performCount总是使用旧值——首次操作文本框内容不变,再次点击才显示上一次操作的结果。但点击按钮触发计算时,能得到正确值。推测是事件触发早于ObservableCollection的数据源更新。
相关代码
XAML代码
<Window x:Class="GridViewTest.MainWindow" 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:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:local="clr-namespace:GridViewTest" mc:Ignorable="d" Title="MainWindow" Height="450" Width="800"> <DockPanel> <GroupBox Header="Data" Grid.Row ="1" Margin="0,0,0,0" DockPanel.Dock="Top" Height="100"> <DataGrid x:Name="dataGrid" Margin="0,0,0,0" AutoGenerateColumns="False" CanUserAddRows="False" CanUserDeleteRows="False" CanUserResizeRows="False" CanUserSortColumns="False" CanUserResizeColumns="False" CanUserReorderColumns="False" VerticalAlignment="Stretch" > <DataGrid.Columns> <DataGridCheckBoxColumn Header="Flag" Binding="{Binding Path=flag}" Width="35" IsReadOnly="false"> <DataGridCheckBoxColumn.CellStyle> <Style> <EventSetter Event="CheckBox.Checked" Handler="UseCheckboxChanged"/> <EventSetter Event="CheckBox.Unchecked" Handler="UseCheckboxChanged"/> </Style> </DataGridCheckBoxColumn.CellStyle> </DataGridCheckBoxColumn> <DataGridTextColumn Header="Value" Binding="{Binding Path=dataValue, StringFormat=N3}" Width="50" IsReadOnly="True"/> </DataGrid.Columns> </DataGrid> </GroupBox> <Button x:Name="myButton" Content="Count" DockPanel.Dock="Top" Height="100" Click="myButton_Click"/> <TextBox x:Name="myTextBox" DockPanel.Dock="Top" Height="25"/> </DockPanel> </Window>
C#代码
namespace GridViewTest { public class Data { private bool _flag; public bool flag { get; set; } public double dataValue { get; set; } public Data() { flag = false; dataValue = 0; } } public partial class MainWindow : Window { ObservableCollection<Data> dataCol = new ObservableCollection<Data>(); public MainWindow() { InitializeComponent(); dataCol = new ObservableCollection<Data>(); Data dataPt1 = new Data(); dataPt1.flag = false; dataPt1.dataValue = 1.23; Data dataPt2 = new Data(); dataPt2.flag = true; dataPt2.dataValue = 2.34; dataCol.Add(dataPt1); dataCol.Add(dataPt2); dataGrid.ItemsSource = dataCol; } private void UseCheckboxChanged(object sender, RoutedEventArgs e) { performCount(); } public void performCount() { int count = 0; double sum = 0; foreach (Data dataPt in dataCol) { if (dataPt.flag) { count++; sum += dataPt.dataValue; } } this.myTextBox.Text = count.ToString() + "|" + sum.ToString(); } private void myButton_Click(object sender, RoutedEventArgs e) { performCount(); } } }
解决方案
问题根源有两个:
- 绑定的更新时机:默认情况下,CheckBox的绑定会在控件失去焦点时才更新源数据,而
Checked/Unchecked事件在状态变更时立即触发,此时源数据还没更新。 Data类未实现INotifyPropertyChanged:无法通知绑定系统属性已变更,导致后续逻辑无法感知数据更新。
修复步骤
1. 让Data类实现INotifyPropertyChanged
这是WPF数据绑定的基础,确保属性变更时能主动通知:
using System.ComponentModel; using System.Runtime.CompilerServices; namespace GridViewTest { public class Data : INotifyPropertyChanged { private bool _flag; public bool flag { get => _flag; set { if (_flag != value) { _flag = value; OnPropertyChanged(); } } } public double dataValue { get; set; } public event PropertyChangedEventHandler PropertyChanged; protected void OnPropertyChanged([CallerMemberName] string propertyName = null) { PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName)); } } }
2. 修改绑定的UpdateSourceTrigger
在XAML中,给CheckBox的绑定添加UpdateSourceTrigger=PropertyChanged,让状态变化时立即更新源数据:
<DataGridCheckBoxColumn Header="Flag" Binding="{Binding Path=flag, UpdateSourceTrigger=PropertyChanged}" Width="35" IsReadOnly="false"> <DataGridCheckBoxColumn.CellStyle> <Style> <EventSetter Event="CheckBox.Checked" Handler="UseCheckboxChanged"/> <EventSetter Event="CheckBox.Unchecked" Handler="UseCheckboxChanged"/> </Style> </DataGridCheckBoxColumn.CellStyle> </DataGridCheckBoxColumn>
3. 可选:改用数据驱动的触发方式(更优雅)
如果不想依赖UI事件,可以直接监听Data对象的PropertyChanged事件,当flag属性变化时自动执行计算。在MainWindow构造函数中添加:
foreach (var dataPt in dataCol) { dataPt.PropertyChanged += DataPt_PropertyChanged; } // 新增事件处理方法 private void DataPt_PropertyChanged(object sender, PropertyChangedEventArgs e) { if (e.PropertyName == nameof(Data.flag)) { performCount(); } }
这种方式脱离UI耦合,更符合WPF的MVVM设计思想,也能确保数据更新后再执行计算。
为什么按钮点击能得到正确值?
因为点击按钮时,焦点已经离开CheckBox,此时绑定的源数据已经完成更新,所以performCount能拿到最新的flag值。
内容的提问来源于stack exchange,提问作者bgarrood
相关产品推荐
相关产品推荐

