OnPropertyChanged вызывается больше после обновления WPF

Мы поддерживаем приложение / элементы управления WPF. Одним из элементов управления является сетка, в которой хранятся числа, пользователь может редактировать ячейки.
В WPF 3.0 все работает нормально.
Теперь мы перешли на WPF 4.5, и один и тот же код ведет себя по- разному: после редактирования ячейки и нажатия клавиши ВВОД вызывает "дополнительное обновление" сетки. Я отладил, и нашел это:

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 его нет. Я думаю, что это должно быть причиной "дополнительного обновления".
Callstack для этого "дополнительного" вызова:

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, поэтому любая справка / подсказка могут быть полезны, что проверять / как вести себя так же, как с WPF3.
Если потребуется какая-либо дополнительная информация, я могу попытаться предоставить.

1 ответ

Решение

В WPF4.5 это вызывает GridContentPropertyChanged чтобы выстрелил, а в WPF3 его нет.

Ну, то GridContentPropertyChanged должен запускаться всякий раз, когда для свойства зависимости установлено новое значение. Это ожидаемое поведение и, очевидно, это было исправлено в более новых версиях.NET Framework. Таким образом, поведение 4.5 является ожидаемым.

Вы можете получить множество исправлений "бесплатно" при обновлении версии.NET. Если это вызывает проблему в вашем приложении, ваш код изначально был написан неправильно. Таким образом, вы можете избежать обновления или исправления кода, как предложено @Peter:

public virtual void OnGridContentChanged(object oldValue, object newValue)
{
    if (oldvalue == newValue)
        return;
     ....
     RebindData(dataGrid);
}
Другие вопросы по тегам