C# WPF DataGrid:在单元格处于编辑状态时添加行会中断编辑关闭检测

C# WPF DataGrid:在单元格处于编辑状态时添加行会中断编辑关闭检测,c#,wpf,datagrid,C#,Wpf,Datagrid,我得到了可以想象得到的最简单的Datagrid,一个按钮绑定到一个命令,该命令向网格所基于的ObservableCollection添加一行。代码非常简单(请参阅下面的MyData类,它只是一堆行) 问题在于: 添加一行 开始编辑名称单元格 按Add(添加)按钮而不退出编辑单元 现在,对单元格结束编辑的检测已中断。 也就是说,您可以去编辑其他单元格,但不会为它们调用setter。 您可以返回到初始编辑行,按enter键;这样做是因为从现在起编辑开始/结束返回工作正常。 同时,已编辑单元格(但第

我得到了可以想象得到的最简单的Datagrid,一个按钮绑定到一个命令,该命令向网格所基于的ObservableCollection添加一行。代码非常简单(请参阅下面的MyData类,它只是一堆行)

问题在于:

  • 添加一行
  • 开始编辑名称单元格
  • 按Add(添加)按钮而不退出编辑单元
  • 现在,对单元格结束编辑的检测已中断。 也就是说,您可以去编辑其他单元格,但不会为它们调用setter。
    您可以返回到初始编辑行,按enter键;这样做是因为从现在起编辑开始/结束返回工作正常。 同时,已编辑单元格(但第一个单元格)的内容将丢失,因为从未调用setter。您所看到的只是图形缓存,所以只需重新排序行并吹!数据不见了

    请注意,为了重现该问题,添加按钮必须将Focusable属性设置为false,否则它会工作,因为单击按钮会使Datagrid失去焦点,因此当添加行发生时,单元格不会处于编辑模式。
    但不可聚焦是工具栏按钮的典型状态,事实上,我第一次在工具栏上看到这个错误

    变通办法 解决方法是将事件关联到代码隐藏中的按钮,以确保datagrid不再处于编辑模式:

    private void Button_Click(object sender, RoutedEventArgs e)
    {
        dg.CommitEdit();
    }
    
    但对于所有可能引发行添加的按钮都是必需的。我想要更健壮的东西,并且我想确保以这种方式添加行不会有问题(应该是主流,但我可能会错过同样的东西)

    XAML 如果不想尝试解决方法,只需删除
    Click=“Button\u 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>
    
    为了完整起见,我的smart 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);
    
    }
    
    公共类RelayCommand:ICommand
    {
    公共事件处理程序CanExecuteChanged;
    公共职能部门;
    公共行动执行;
    public bool CanExecute(对象参数)=>CanExecuteFunc?.Invoke(参数)??true;
    public void Execute(对象参数)=>ExecuteAction?.Invoke(参数);
    }
    
    您可以将绑定的
    更新资源记录器
    设置为
    属性更改
    以立即设置源属性:

    private void dg_AutoGeneratingColumn(object sender, DataGridAutoGeneratingColumnEventArgs e)
    {
        if (e.Column is DataGridTextColumn textColumn)
            textColumn.Binding = new Binding(e.PropertyName) { UpdateSourceTrigger = UpdateSourceTrigger.PropertyChanged };
    }
    
    或者您可以在
    Person
    类中实现。

    您可能需要添加到
    Person
    。这应该通过
    ObservableCollection
    Binding
    自动发现。可能相关
    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);
    
    }
    
    private void dg_AutoGeneratingColumn(object sender, DataGridAutoGeneratingColumnEventArgs e)
    {
        if (e.Column is DataGridTextColumn textColumn)
            textColumn.Binding = new Binding(e.PropertyName) { UpdateSourceTrigger = UpdateSourceTrigger.PropertyChanged };
    }