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

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();
    }
  }
}
解决方案

问题根源有两个:

  1. 绑定的更新时机:默认情况下,CheckBox的绑定会在控件失去焦点时才更新源数据,而Checked/Unchecked事件在状态变更时立即触发,此时源数据还没更新。
  2. 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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.19 06:50:24