【发布时间】:2020-11-17 23:08:36
【问题描述】:
我有一个可以想象的最简单的 Datagrid,一个按钮绑定到一个命令,该命令将一行添加到网格所基于的 ObservableCollection。代码真的很简单(参见下面的 MyData 类,它只是一堆代码)。
错误是这样的:
- 添加一行
- 开始编辑名称单元格
- 在不退出编辑单元格的情况下按添加按钮
现在单元格结束编辑的检测被破坏了。
也就是说,您可以去编辑其他单元格,但不会调用 setter。
可以回到最初的编辑行,回车;这种修复的事情,因为从现在开始编辑开始/结束返回正常工作。
与此同时,已编辑单元格的内容(但第一个单元格)丢失了,因为从未调用过 setter。你看到的只是图形缓存,所以只需重新排序行和粉扑!数据消失了。
请注意,为了重现问题,添加按钮必须将 Focusable 属性设置为 false,否则它会起作用,因为单击按钮会使 Datagrid 失去焦点,因此当添加-行发生时,单元格未处于编辑模式。
但是不可聚焦是 ToolBar 按钮的典型状态,事实上我第一次看到这个 bug 是 ToolBar。
解决方法
一种解决方法是将事件关联到代码隐藏中的按钮,以确保数据网格不再处于编辑模式:
private void Button_Click(object sender, RoutedEventArgs e)
{
dg.CommitEdit();
}
但对于所有可能触发添加行的按钮都是必需的。我想要更健壮的东西,并且我想确保以这种方式添加行没有问题(应该是主流,但我可能会错过同样的东西)。
XAML
如果您不想尝试解决方法,只需删除 Click="Button_Click"。
<Window x:Class="WpfApp10_DataGridEditingBug.MainWindow"
...
Title="MainWindow" Height="140" Width="280">
<Window.DataContext>
<local:MyData></local:MyData>
</Window.DataContext>
<DockPanel>
<StackPanel DockPanel.Dock="Top" Orientation="Horizontal">
<Button Command="{Binding AddCommand}" Focusable="False" Click="Button_Click">Add</Button>
</StackPanel>
<DataGrid x:Name="dg" ItemsSource="{Binding People}" CanUserAddRows="False">
</DataGrid>
</DockPanel>
</Window>
数据上下文
public class MyData
{
public ObservableCollection<Person> People { get; } = new ObservableCollection<Person>();
public RelayCommand AddCommand => addCommand ?? (addCommand = new RelayCommand() { ExecuteAction = AddCommandExecute });
private void AddCommandExecute(object obj)
{
var newPerson = new Person();
People.Add(newPerson);
}
private RelayCommand addCommand;
}
行类
我只是几个属性名称和姓氏的主机类。出于调试的原因,我没有使用自动属性,这种方式更容易发现它甚至不会通过在此处设置断点来调用 name 属性的 set 方法。
public class Person
{
public string Name
{
get => name;
set => name = value;
}
private string name;
public string Surname
{
get => surname;
set => surname = value;
}
private string surname;
}
而且,为了完整起见,我的智能 RelayCommand 实现是这样的:
public class RelayCommand : ICommand
{
public event EventHandler CanExecuteChanged;
public Func<object, bool> CanExecuteFunc;
public Action<object> ExecuteAction;
public bool CanExecute(object parameter) => CanExecuteFunc?.Invoke(parameter) ?? true;
public void Execute(object parameter) => ExecuteAction?.Invoke(parameter);
}
【问题讨论】:
-
您可能需要将
IEditableObject添加到Person。这应该会被ObservableCollection和Binding自动发现。可能相关 WPF ObservableCollection Edit Mode