单击DataGrid行中的复选框时触发PropertyChanged事件

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了单击DataGrid行中的复选框时触发PropertyChanged事件相关的知识,希望对你有一定的参考价值。

我有一个看起来像这样的DataGrid:

<DataGrid Name="Users" ItemsSource="{Binding Users, Mode=TwoWay}" 
          AutoGenerateColumns="False" Grid.ColumnSpan="2" CanUserAddRows="False">
    <DataGrid.Columns>
        <DataGridTemplateColumn>
            <DataGridTemplateColumn.Header>
                <CheckBox Name="SelectAllUsers" 
                          Checked="SelectAllUsers_Checked" 
                          Unchecked="SelectAllUsers_Unchecked"/>
            </DataGridTemplateColumn.Header>
            <DataGridTemplateColumn.CellTemplate>
                <DataTemplate>
                    <CheckBox x:Name="SelectUser" 
                              IsChecked="{Binding IsSelected, Mode=TwoWay}" 
                              Checked="SelectUser_Checked" 
                              Unchecked="SelectUser_Unchecked"/>
                </DataTemplate>
            </DataGridTemplateColumn.CellTemplate>
        </DataGridTemplateColumn>
        <DataGridTextColumn x:Name="UserName" 
                            Binding="{Binding UserName}" 
                            Header="Name" IsReadOnly="True"/>
    </DataGrid.Columns>
</DataGrid>

它目前在ViewModel中与BindingList数据绑定:

class SecurityDialogViewModel
{
    public BindingList<User> Users { get; set; }

User是一个带有INotifyPropertyChanged实现的DTO(Fody.PropertyChanged):

[AddINotifyPropertyChangedInterface]
class User
{
    public int UserId { get; set; }
    public string UserName { get; set; }
    public bool IsSelected { get; set; }
}

SelectAllUsers_Checked在ViewModel中有一些代码,它们将所有复选框设置为true,然后根据Users BindingList集合中的复选框选项调用ViewModel中的方法来执行一些魔法(现在全部都被选中):

private void SelectAllUsers_Checked(object sender, RoutedEventArgs e)
{
    SelectAll(Users, true);
    (DataContext as MyViewModel).PerformMagic();
}

private void SelectAll(DataGrid dataGrid, bool value)
{
    foreach (dynamic d in dataGrid.ItemsSource)
    {
        d.IsSelected = value;
    }
}

一切都很好。但是,检查单个用户不会。基础绑定列表显然未经修改:

private void SelectUser_Checked(object sender, RoutedEventArgs e)
{
    (DataContext as MyViewModel).PerformMagic(); // Doesn't execute
}

我以为我知道为什么。在你离开记录之前,BindingList不会触发PropertyChanged事件。但是取消选中另一行上的另一个复选框(从而移出原始记录并据称触发PropertyChanged事件)也没有效果。

我真正需要的是一个集合,它会在单击一个DataGrid行复选框时触发PropertyChanged事件。

我该怎么做呢?我可以将ObservableCollection子类化并捕获其中一个事件吗?或者我需要自己写吗?也许我可以简单地将一个事件挂钩到现在没有被观察到的现有ObservableCollection上?

答案

好吧,解决方案比我想象的要简单得多:

private void SelectUser_Checked(object sender, RoutedEventArgs e)
{
    var binding = (sender as CheckBox).GetBindingExpression(CheckBox.IsCheckedProperty);
    binding.UpdateSource(); // Triggers PropertyChanged Notification

    (DataContext as MyViewModel).PerformMagic();    
}

这也有效:

<CheckBox 
      x:Name="SelectUser" 
      IsChecked="{Binding IsSelected, UpdateSourceTrigger=PropertyChanged}" />

注意事项

BindableList有自己的问题。

  • 你不能从DataGrid应用排序,这意味着你必须subclass it if you want this capability
  • 它可能会在某些条件下导致内存泄漏;特别是,BindingList没有实现INotifyCollectionChanged,如果绑定到控件的ItemsSource属性,将导致内存泄漏。

最终我决定使用ObservableCollection并在代码隐藏中执行事件处理,而不是尝试依赖数据绑定事件。结果是更简单,更容易掌握,不需要任何特殊的集合子类,我得到了我想要的精细控制。

进一步阅读 The UpdateSourceTrigger property Sortable BindingList Implementation Another Sortable BindingList Implementation

以上是关于单击DataGrid行中的复选框时触发PropertyChanged事件的主要内容,如果未能解决你的问题,请参考以下文章

如何删除 Material UI DataGrid (Reactjs) 中的特定行

您可以在自动排序DataGrid中更改列的初始排序方向吗?

复选框上的多行选择和单击 MUI DataGrid 中的行时的单选

从视图模型中选择数据网格行中的所有复选框

c# wpf datagrid中选择所有复选框的代码

EasyUi datagrid(onClickCell:用户单击一个单元格时触发 ) 單擊編輯 editor:{type: 'combobox'}