【发布时间】: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 已经提供了按点击的列排序。