WPF 升级后 OnPropertyChanged 调用更多

OnPropertyChanged called more after WPF upgrade

我们维护一个 WPF app/controls。其中一个控件是存储数字的网格,用户可以编辑单元格。
在 WPF 3.0 中,它工作正常。
现在我们转移到 WPF 4.5,相同的代码表现 不同 :在编辑单元格并按下 ENTER 后,它会导致网格 "extra refresh"。 我调试了,发现这个:

public List<List<double>> DoubleArray { get; set; }

private void dataGrid2D_CellEditEnding(object sender, Microsoft.Windows.Controls.DataGridCellEditEndingEventArgs e)
{
     ...
     DoubleArray[y][x] = double.Parse(textBox.Text);
     GridContent = DoubleArray; <======= [this line]
     ...
}

public static readonly DependencyProperty GridContentProperty =
        DependencyProperty.Register("GridContent", typeof(IList), typeof(GridEditor), 
                             new UIPropertyMetadata(null,GridContentPropertyChanged));

public IList GridContent
{
    get { return (IList)GetValue(GridContentProperty); }
    set { SetValue(GridContentProperty, value); }
}

private static void GridContentPropertyChanged(DependencyObject source, DependencyPropertyChangedEventArgs e)
{
    GridEditor editor = source as GridEditor;
    editor.OnGridContentChanged(e.OldValue,e.NewValue);
}

public virtual void OnGridContentChanged(object oldValue, object newValue)
{
     ....
     RebindData(dataGrid);
}

private void RebindData(DataGrid2DLibrary.DataGrid2DT grid)
{
    Binding datagrid2dBinding = new Binding();
    .....
    datagrid2dBinding.Path = new PropertyPath("DoubleArray");
    grid.SetBinding(DataGrid2DT.ItemsSource2DProperty, datagrid2dBinding);
 }

标记的行 GridContent = DoubleArray; 在 WPF3 和 WPF4.5 中运行不同。
在 WPF4.5 中,它会触发 GridContentPropertyChanged,而在 WPF3 中则不会。我想这应该是 "extra refresh".
的原因 此 "extra" 调用的调用堆栈:

OurEditor.dll!OurEditor.GridEditor.GridEditor.OnGridContentChanged(object oldValue, object newValue) Line 345   C#
OurEditor.dll!OurEditor.GridEditor.GridEditor.GridContentPropertyChanged(System.Windows.DependencyObject source, System.Windows.DependencyPropertyChangedEventArgs e) Line 120  C#
WindowsBase.dll!System.Windows.DependencyObject.OnPropertyChanged(System.Windows.DependencyPropertyChangedEventArgs e)  Unknown
PresentationFramework.dll!System.Windows.FrameworkElement.OnPropertyChanged(System.Windows.DependencyPropertyChangedEventArgs e)    Unknown
WindowsBase.dll!System.Windows.DependencyObject.NotifyPropertyChange(System.Windows.DependencyPropertyChangedEventArgs args)    Unknown
WindowsBase.dll!System.Windows.DependencyObject.UpdateEffectiveValue(System.Windows.EntryIndex entryIndex, System.Windows.DependencyProperty dp, System.Windows.PropertyMetadata metadata, System.Windows.EffectiveValueEntry oldEntry, ref System.Windows.EffectiveValueEntry newEntry, bool coerceWithDeferredReference, bool coerceWithCurrentValue, System.Windows.OperationType operationType) Unknown
WindowsBase.dll!System.Windows.DependencyObject.InvalidateProperty(System.Windows.DependencyProperty dp, bool preserveCurrentValue) Unknown
PresentationFramework.dll!System.Windows.Data.BindingExpressionBase.Invalidate(bool isASubPropertyChange)   Unknown
PresentationFramework.dll!System.Windows.Data.BindingExpression.TransferValue(object newValue, bool isASubPropertyChange)   Unknown
PresentationFramework.dll!System.Windows.Data.BindingExpression.ScheduleTransfer(bool isASubPropertyChange) Unknown
PresentationFramework.dll!MS.Internal.Data.ClrBindingWorker.NewValueAvailable(bool dependencySourcesChanged, bool initialValue, bool isASubPropertyChange)  Unknown
PresentationFramework.dll!MS.Internal.Data.PropertyPathWorker.UpdateSourceValueState(int k, System.ComponentModel.ICollectionView collectionView, object newValue, bool isASubPropertyChange)   Unknown
PresentationFramework.dll!MS.Internal.Data.PropertyPathWorker.RefreshValue()    Unknown
PresentationFramework.dll!MS.Internal.Data.ClrBindingWorker.RefreshValue()  Unknown
PresentationFramework.dll!System.Windows.Data.BindingExpression.UpdateTarget()  Unknown
PresentationFramework.dll!System.Windows.Data.BindingExpressionBase.EndSourceUpdate()   Unknown
PresentationFramework.dll!System.Windows.Data.BindingExpression.UpdateSource(object value)  Unknown
PresentationFramework.dll!System.Windows.Data.BindingExpressionBase.UpdateValue()   Unknown
PresentationFramework.dll!System.Windows.Data.BindingExpression.UpdateOverride()    Unknown
PresentationFramework.dll!System.Windows.Data.BindingExpressionBase.Update()    Unknown
PresentationFramework.dll!System.Windows.Data.BindingExpressionBase.ProcessDirty()  Unknown
PresentationFramework.dll!System.Windows.Data.BindingExpressionBase.Dirty() Unknown
PresentationFramework.dll!System.Windows.Data.BindingExpressionBase.SetValue(System.Windows.DependencyObject d, System.Windows.DependencyProperty dp, object value) Unknown
WindowsBase.dll!System.Windows.DependencyObject.SetValueCommon(System.Windows.DependencyProperty dp, object value, System.Windows.PropertyMetadata metadata, bool coerceWithDeferredReference, bool coerceWithCurrentValue, System.Windows.OperationType operationType, bool isInternal)    Unknown
WindowsBase.dll!System.Windows.DependencyObject.SetValue(System.Windows.DependencyProperty dp, object value)    Unknown
OurEditor.dll!OurEditor.GridEditor.GridEditor.GridContent.set(System.Collections.IList value) Line 114  C#
OurEditor.dll!OurEditor.GridEditor.GridEditor.dataGrid2D_CellEditEnding(object sender, Microsoft.Windows.Controls.DataGridCellEditEndingEventArgs e) Line 674   C#

XAML这个编辑器的使用方法:

<ControlTemplate x:Key="GridEditorTemplate">
    <ge:GridEditor IsReadOnly="{Binding IsOutput, RelativeSource={RelativeSource AncestorType={x:Type vo:OutputView}}}">
        <me:GridEditor.GridContent>
            <Binding Path="TheGridValue"  Mode="TwoWay" Converter="{StaticResource gridConverter}">
            </Binding> 
         </me:GridEditor.GridContent>
    </me:GridEditor>
</ControlTemplate>

我对 WPF 不是很熟悉,所以任何 help/hint 都可能对 check/how 具有与 WPF3 相同的 "proper" 行为有用。
如果需要任何其他信息,我可以尝试提供。

In WPF4.5, it causes the GridContentPropertyChanged to fired, while in WPF3 it does not.

好吧,只要将依赖项 属性 设置为新值,就应该触发 GridContentPropertyChanged。这是预期的行为,显然这已在较新版本的 .NET Framework 中得到修复。所以 4.5 行为是预期的行为。

当您升级 .NET 版本时,您可能会得到很多修复 "for free"。如果这导致您的应用程序出现问题,则您的代码最初可能以错误的方式编写。因此,您可以避免按照@Peter 的建议升级或修复您的代码:

public virtual void OnGridContentChanged(object oldValue, object newValue)
{
    if (oldvalue == newValue)
        return;
     ....
     RebindData(dataGrid);
}