【问题标题】:WPF DataGrid calls BeginEdit on an IEditableObject two times?WPF DataGrid 在 IEditableObject 上调用 BeginEdit 两次?
【发布时间】:2011-05-25 22:51:26
【问题描述】:

我有一个绑定到 IEditableObject 集合的 DataGrid。

现在当我在一个单元格中单击两次时,它将打开以进行编辑。

有趣的是:BeginEdit 会被调用两次。有时对于同一个 EditableObject,但有时对于两个不同的对象(特别是当我使用 PgDn 直到我到达 DataGrid 的末尾时)会首先调用正确的对象,然后是集合中的其他一些项目,这些项目以前从未成为焦点.

EndEdit 也被调用了两次,但总是针对选定的项目,而不是针对错误的项目。

这是一个已知问题吗?仅获得(正确)一个通知的任何解决方法。

【问题讨论】:

  • 听起来很有趣,所以我检查了我的 DataGrid,它也绑定到 ObservableCollection 并且没有遇到这种情况......?我的表示是每行一个对象,您是否偶然合并了都实现 IEditableObject 或类似的对象?
  • 有趣。我的对象只实现了 IEditableObject 和 INotifyPropertyChanged,所以没有合并。不过,我的 ObservableCollection 被包装到自定义 ListCollectionView 中。而且我确实将 Column 绑定到 IEditableObject 中的类中的属性,而不是直接绑定到 IEditableObject 的属性。至少现在我有理由检查我的来源,谢谢!
  • MSDN 示例始终包含一个标志,该标志可防止 BeginEdit 在除第一次以外的任何时间调用时执行其操作。根据我的经验,是的,它被多次调用。

标签: wpf datagrid ieditableobject


【解决方案1】:

如果您在调用BeginEdit 时查看调试器中的堆栈跟踪,您会看到第一次是集合视图调用它,第二次是BindingGroup

问题似乎是有两件事都认为他们负责IEditableObject 状态。当 WPF 提供默认集合视图时,它将在集合中的对象上查找 IEditableObject,并将调用 BeginEditEndEditCancelEdit 以响应对相应 IEditableCollectionView 方法的调用。而且,BindingGroup 将调用IEditableObject 方法以响应对BeginEditCommitEditCancelEdit 的调用。

DataGrid 使用这两个功能:当您连续开始和完成编辑时,它会通知IEditableCollectionView BindingGroup,这两件事都认为这是他们的责任转到继续并通知底层源对象上的IEditableObject 实现。

所以它看起来很像DataGrid 中的一个错误——它导致两个不同的对象调用BeginEdit(和相关方法)。这是因为它利用了可编辑的集合视图和绑定组——从外观上看,它们并不是为了在同一对象上同时使用而设计的,就像DataGrid 使用它们的方式一样。

您在 Toolkit 中没有看到网格存在此问题的原因是它似乎是一个稍旧的版本 - 将其中的代码与 Reflector 为 .NET 4.0 显示的代码进行比较,您会看到 . NET 4.0 DataGrid 有一些额外的代码(一种新方法 EnsureItemBindingGroup,以及 MeasureOverrideOnRowValidationRulesChanged 中的一些相关代码)确保绑定组始终存在,无论您是否要求。因此,如果 WPF 工具包被更新,它可能会增加一个类似的功能,除非这个问题得到修复。 (而且我猜想,如果您使用 WPF 工具包的当前版本(我写这篇文章时 2010 年 2 月),并且使用 ItemBindingGroup 属性显式询问绑定组,您会看到完全相同的问题。 )

这并没有解释您如何在您所描述的随机对象上调用BeginEdit。我无法重现。但它确实解释了对所选对象的双重调用。最好的办法似乎是对源对象进行编码,以便它们能够容忍双重调用。

【讨论】:

    【解决方案2】:

    我不确定你会在 BeginEdit 事件发生之前用什么来中断它,但对于 EndEdit,一个简单的 isDirty 标记就可以了。在实现 IEditableObject 的 Entity 类中,添加以下内容:

        private bool _isDirty = false;
    
        #region IEditableObject Members
    
        public void BeginEdit()
        {
            // Bug Fix: Windows Controls call EndEdit twice; Once
            // from IEditableCollectionView, and once from BindingGroup.
            // This makes sure it only happens once after a BeginEdit.
            _isDirty = true;
        }
    
        public void CancelEdit() { }
    
        public void EndEdit()
        {
            if (ItemEndEdit != null && _isDirty)
            {
                _isDirty = false;
                ItemEndEdit(this);
            }
        }
    
        #endregion
    

    【讨论】:

    • 您应该在 CancelEdit 方法中设置 _isDirty=false。
    【解决方案3】:

    我在使用 .NET Framework 4 DataGrid 时遇到了同样的问题。

    添加对 WPFToolkit 最新版本的引用

    添加

    xmlns:dg="clr-namespace:Microsoft.Windows.Controls;assembly=WPFToolkit"
    

    并将<DataGrid> 更改为<dg:DataGrid>

    【讨论】:

    • 酷,有趣。这是一个不同的版本,还是为什么这能解决问题??
    【解决方案4】:

    +1 @IanGriffiths 用于诊断问题。至于解决方案(或解决方法),您可以计算“待处理”编辑的数量。这意味着类似:

    void BeginEdit()
    {
        _numEdits++;
    }
    
    void CancelEdit()
    {
        if(--_numEdits < 0)
            throw new Exception("WTF?"); 
    }
    
    void EndEdit()
    {
        CancelEdit();
        if(_numEdits == 0)
            commitEdit();
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2014-08-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-08-10
      • 2012-06-24
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多