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

标签 c# wpf mvvm

我有一个看起来像这样的 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>

它目前数据绑定(bind)到 BindingList在 View 模型中:
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,然后调用 ViewModel 中的方法以根据用户 BindingList 集合中的复选框选择执行一些魔术(现在全部选中):
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;
    }
}

这一切都很好。但是,检查单个用户不会。底层绑定(bind)列表显然保持不变:
private void SelectUser_Checked(object sender, RoutedEventArgs e)
{
    (DataContext as MyViewModel).PerformMagic(); // Doesn't execute
}

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

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

我该怎么做呢?我可以将 ObservableCollection 子类化吗?并捕捉其中一个事件?还是我需要自己写?也许我可以简单地将一个事件 Hook 到现有的 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如果绑定(bind)到控件的 ItemsSource 将导致内存泄漏属性(property)。

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

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

    关于c# - 单击 DataGrid 行中的复选框时触发 PropertyChanged 事件,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/49017596/

    相关文章:

    c# - 尝试在 C# 中执行按键事件时出错

    WPF 绑定(bind)今天减去 7 天

    wpf - XAML 文本框在焦点上更改边框颜色

    java - DiffCallBack不被调用吗?

    c# - 为什么我的 C# "hello world"COM 客户端和服务器会抛出强制转换异常?

    c# - 无法在 LINQ to Entities 查询中初始化实现 IEnumerable 'System.Collections.Generic.List` 1' 的类型

    c# - 使用不同的编码器选择格式时删除 EXIF 不起作用

    无法识别 wpf 自定义控件

    wpf - 如何将命令绑定(bind)到复选框

    xamarin.forms - 如何从 Xamarin 表单中的 DataTemplate 条目 TextChanged 事件调用命令?