【问题标题】:OnPropertyChanged called more after WPF upgradeWPF 升级后调用更多 OnPropertyChanged
【发布时间】:2017-06-29 11:14:25
【问题描述】:

我们维护一个 WPF 应用程序/控件。其中一个控件是存储数字的网格,用户可以编辑单元格。
在 WPF 3.0 中,它工作正常。
现在我们移至 WPF 4.5,相同的代码表现出不同:在编辑单元格并按 ENTER 后,它会导致网格“额外刷新”。 我调试了一下,发现了这个:

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 中则不会。我想这应该是“额外刷新”的原因。
此“额外”调用的调用堆栈:

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 相同的“正确”行为有用。
如果需要任何其他信息,我可以尝试提供。

【问题讨论】:

  • 如何使用if(oldvalue == newValue) return;
  • 是的,这可能是一种可以考虑作为解决方法的方法,但我想这种行为改变应该有根本原因,最好根据它进行改变。

标签: wpf binding grid dependency-properties


【解决方案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);
}

【讨论】:

  • 这个建议不起作用,因为当您更改任何单元格时,显然是oldValue != newValue。但是,比较 DoubleArray == newValue 就可以了。
  • 嗯,实际比较只是一个例子。重点是处理程序将被解雇。
  • 感谢澄清,我按照自己的逻辑进行了修正,但现在很清楚为什么会发生这种情况。
  • 不客气,但请记得投票给有用的答案:) stackoverflow.com/help/privileges/vote-up
猜你喜欢
  • 2022-01-13
  • 2018-12-13
  • 2011-03-04
  • 2016-01-10
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多