【问题标题】:WPF DataGrid: adding a row while a cell is in edit breaks the edit-close detectionWPF DataGrid:在编辑单元格时添加一行会破坏编辑关闭检测
【发布时间】:2020-11-17 23:08:36
【问题描述】:

我有一个可以想象的最简单的 Datagrid,一个按钮绑定到一个命令,该命令将一行添加到网格所基于的 ObservableCollection。代码真的很简单(参见下面的 MyData 类,它只是一堆代码)。

错误是这样的:

  1. 添加一行
  2. 开始编辑名称单元格
  3. 在不退出编辑单元格的情况下按添加按钮

现在单元格结束编辑的检测被破坏了。 也就是说,您可以去编辑其他单元格,但不会调用 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);

}

【问题讨论】:

标签: c# wpf datagrid


【解决方案1】:

您可以将绑定的UpdateSourceTrigger 设置为PropertyChanged 以立即设置源属性:

private void dg_AutoGeneratingColumn(object sender, DataGridAutoGeneratingColumnEventArgs e)
{
    if (e.Column is DataGridTextColumn textColumn)
        textColumn.Binding = new Binding(e.PropertyName) { UpdateSourceTrigger = UpdateSourceTrigger.PropertyChanged };
}

或者你可以在你的Person 类中实现IEditableObject

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2012-12-04
    • 1970-01-01
    • 2011-11-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多