【问题标题】:Trigger a PropertyChanged event the moment a checkbox in a DataGrid row is clicked单击 DataGrid 行中的复选框时触发 PropertyChanged 事件
【发布时间】:2018-08-07 15:02:27
【问题描述】:

我有一个如下所示的 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,然后调用 ViewModel 中的一个方法,根据 Users 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;
    }
}

这一切都很好。但是,检查单个用户不会。底层绑定列表显然保持不变:

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

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

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

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

【问题讨论】:

  • 您似乎是通过在SelectAll 中设置IsSelected = value 来手动触发属性更改事件。您是否尝试过为SelectUser_Checked 创建类似的方法?我认为您唯一需要的就是确定检查了哪个选项的方法。
  • @Sudsy1002: IsSelected 没有被直接设置。 SelectAll 正在检查代码隐藏中的所有 DataGrid 复选框,并且数据绑定正在设置底层 User 集合记录。
  • 也许我不明白,但是从SelectAll 中的代码中,您将Users 作为数据网格传入。然后将 Users 中的每个 User.IsSelected 设置为 true。为什么你不能做同样的事情,但只对选中的用户,在一个单独的方法中,比如 SelectOne,然后从 SelectUser_Checked 调用 SelectOne,就像你从 SelectAllUsers_Checked 调用 SelectAll 一样?
  • @Sudsy1002:因为我会在点击事件处理程序中设置复选框,编码相当于咬我自己的牙齿。它还会导致无限循环。请参阅下面的答案。
  • @XAMlMAX 我确实考虑使用CollectionViewSource 进行过滤,但我需要比 Linq 语句提供的更好的控制。 DataGrid 已经提供了按点击的列排序。

标签: c# wpf mvvm


【解决方案1】:

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

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

【讨论】:

  • 请注意,ToggleButton.IsChecked 属性默认绑定 TwoWay。默认情况下,UpdateSourceTrigger 也应该是 PropertyChanged。
  • @Clemens:如果删除 UpdateSourceTrigger 部分,行为会发生变化。选中复选框时不再触发数据绑定。
猜你喜欢
  • 2015-08-09
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-12-22
  • 2018-03-12
  • 2012-01-15
  • 1970-01-01
相关资源
最近更新 更多