C# WPF DataGrid-验证错误后如何取消编辑行?

C# WPF DataGrid-验证错误后如何取消编辑行?,c#,wpf,datagrid,C#,Wpf,Datagrid,我想在用户单击时取消行中的更改✖ 按钮 private void CancelChangesButton_单击(对象发送方,路由目标) { datagrid.CancelEdit(); } CancelEdit()非常有效,直到。。。my DateConverter无法转换回字符串。当ViewModel的属性设置程序引发异常时,也会发生相同的行为。 我不能在DataGrid中做任何事情。唯一的方法是在光标位于红色单元格中时按ESC键 我试着做其他事情: datagrid.CancelEdit

我想在用户单击时取消行中的更改✖ 按钮

private void CancelChangesButton_单击(对象发送方,路由目标)
{
datagrid.CancelEdit();
}
CancelEdit()非常有效,直到。。。my DateConverter无法转换回字符串。当ViewModel的属性设置程序引发异常时,也会发生相同的行为。 我不能在DataGrid中做任何事情。唯一的方法是在光标位于红色单元格中时按ESC键

我试着做其他事情:

datagrid.CancelEdit(DataGridEditingUnit.Row);
datagrid.CancelEdit(DataGridEditingUnit.Cell);
datagrid.committedit();
datagrid.IsReadOnly=true;
//添加新项目
什么也没发生

因此,我开始挖掘.NET Framework的源代码,我发现:

公共类数据网格:多选择器
...
公共布尔取消编辑(DataGridEditingUnit editingUnit)
{
返回EndEdit(CancelEditCommand,CurrentCellContainer,editingUnit,true);
}

这里最重要的是CurrentCellContainer,它从CurrentCell获取值。接下来,我发现CurrentCell正在跟踪焦点。当我点击✖ 按钮,CurrentCell将更改为Action列中的单元格,当我单击DataGrid外部时,CurrentCell将更改为null

因此,我必须将CurrentCell更改为带有验证错误的单元格,然后调用CancelEdit()。 我认为对吗

如何查找存在验证错误的所有单元格?


是否有其他方法取消编辑?

红细胞显示验证错误。只要存在验证错误(用户按Escape键除外),就不能取消编辑模式

唯一的解决方案是通过简单地恢复输入手动解决错误

算法如下:

  • 获取当前单元格
  • 获取当前单元格的容器
  • 检查容器(单元格)是否存在验证错误。如果是,继续执行步骤4,否则取消编辑(跳到步骤9)
  • 获取单元格模板的编辑
    文本框
  • 标识编辑
    TextBox.Text的绑定源(数据项)属性
  • 获取属性的值(对泛型行为使用反射)
  • 还原内容
  • 将键盘焦点移回编辑
    文本框
    ,它将触发重新验证并定义取消的目标单元格
  • 取消编辑
  • 实施:

    private void CancelChangesButton_Click(object sender, RoutedEventArgs e)
    {
      DependencyObject cellItemContainer = this.datagrid.ItemContainerGenerator.ContainerFromItem(
        (this.datagrid.CurrentCell.Item as SomethingItem));
    
      // If the current cell has validation errors find the edit TextBox child control
      if (Validation.GetHasError(cellItemContainer) && TryFindChildElement(cellItemContainer, out TextBox editTextBox))
      {
        // Get the property name of he binding source
        var propertyName = (editTextBox.BindingGroup.BindingExpressions.FirstOrDefault() as BindingExpression)?.ResolvedSourcePropertyName ?? string.Empty;
    
        // Use reflection to get the value of the binding source
        object value = this.datagrid.CurrentCell.Item.GetType().GetProperty(propertyName).GetValue(this.datagrid.CurrentCell.Item);
    
        // Check which ToString() to invoke
        editTextBox.Text = value is DateTime date 
          ? date.ToShortDateString() 
          : value.ToString();
    
        // Trigger validation and define which cell to cancel the edit
        // This is required because the edit TexBox lost focus
        Keyboard.Focus(editTextBox);
      }
    
      this.datagrid.CancelEdit();
    }
    
    // Traverses the visual tree to find a child element of type TElement
    private bool TryFindVisualChild<TChild>(DependencyObject parent, out TChild resultElement) where TChild : DependencyObject
    {
      resultElement = null;
      for (var childIndex = 0; childIndex < VisualTreeHelper.GetChildrenCount(parent); childIndex++)
      {
        DependencyObject childElement = VisualTreeHelper.GetChild(parent, childIndex);
    
        if (childElement is Popup popup)
        {
          childElement = popup.Child;
        }
    
        if (childElement is TChild)
        {
          resultElement = childElement as TChild;
          return true;
        }
    
        if (TryFindVisualChild(childElement, out resultElement))
        {
          return true;
        }
      }
    
      return false;
    }
    
    private void CancelChangesButton_单击(对象发送方,路由目标)
    {
    DependencyObject cellItemContainer=this.datagrid.ItemContainerGenerator.ContainerFromItem(
    (this.datagrid.CurrentCell.Item作为SomethingItem));
    //如果当前单元格存在验证错误,请查找编辑文本框子控件
    if(Validation.GetHasError(cellItemContainer)和&TryFindChildElement(cellItemContainer,out TextBox editTextBox))
    {
    //获取绑定源的属性名称
    var propertyName=(editTextBox.BindingGroup.BindingExpressions.FirstOrDefault()作为BindingExpression)?。ResolvedSourcePropertyName??string.Empty;
    //使用反射获取绑定源的值
    对象值=this.datagrid.CurrentCell.Item.GetType().GetProperty(propertyName).GetValue(this.datagrid.CurrentCell.Item);
    //检查要调用哪个ToString()
    editTextBox.Text=值为日期时间日期
    ?date.ToShortDateString()
    :value.ToString();
    //触发验证并定义要取消编辑的单元格
    //这是必需的,因为编辑框失去焦点
    键盘。焦点(编辑文本框);
    }
    this.datagrid.CancelEdit();
    }
    //遍历可视化树以查找TElement类型的子元素
    private bool TryFindVisualChild(DependencyObject父对象,out TChild resultElement),其中TChild:DependencyObject
    {
    resultElement=null;
    对于(var childIndex=0;childIndex
    我意识到我不需要找到有验证错误的单元格。我只需要对所有单元格调用CancelEdit()

    private void CancelChangesButton_单击(对象发送方,路由目标)
    {
    var cc=dataGrid.CurrentCell;
    foreach(datagrid.Columns中的var col)
    {
    datagrid.CurrentCell=新的DataGridCellInfo(datagrid.CurrentItem,col);
    datagrid.CancelEdit();
    }
    dataGrid.CurrentCell=cc;
    }
    
    它还可以使用DataGridTemplateColumn。


    但是,如果您想找到哪些单元格包含验证错误,则需要深入查看。多亏了@BionicCode,我找到了一个解决方案

    您可以获得可视化DataGridRow:

    DataGridRow行=(DataGridRow)datagrid.ItemContainerGenerator.ContainerFromItem(item);
    
    然后,您可以检查错误:

    if(Validation.gethasrerror(行))
    
    您还可以访问
    行.BindingGroup
    ,其中包含此行中的所有绑定(.BindingExpressions),以及许多其他信息(IsDirty、ValidationErrors、ValidationRules、CancelEdit()

    但是,当您想要检查单元格中的错误时,这并不是那么容易。不幸的是,DataGridCell不包含有关错误的信息,
    Validation.GetHasError(单元格)
    不工作。您需要更深入地查看可视化树

    private void cancelchangescellshoodingerror()
    {
    SomethingItem item=datagrid.CurrentItem作为SomethingItem;
    DataGridRow行=(DataGridRow)datagrid.ItemContainerGenerator.ContainerF