子对象 属性 更改会触发父 DependencyPropertyChanged 回调?
Child object property change fires parents DependencyPropertyChanged callback?
在定义继承 Animatable
、class 的基础 class 时,我发现了一些奇怪的行为。
当我在 'Parent' class 中创建子 DependencyProperty 时,然后定义该 'Parent' class 的实例,然后更改 属性 parents child,我为 Parents Child 属性 定义的 PropertyChangedCallback 触发。
符合要求 Minimal, Complete and Verifiable Example:
using System;
using System.Collections.Generic;
using System.Windows;
using System.Windows.Media.Animation;
namespace MCVE {
/// <summary>
/// Interaction logic for App.xaml
/// </summary>
public partial class Program {
[STAThread]
public static int Main( ) {
Parent p = new Parent( );
p.Child.Trigger = new object( );
return 0;
}
}
public abstract class Base : Animatable {
public static readonly DependencyProperty TriggerProperty;
static Base( ) =>
TriggerProperty = DependencyProperty.Register(
"Trigger", typeof( object ), typeof( Base) );
public object Trigger {
get => this.GetValue( TriggerProperty );
set => this.SetValue( TriggerProperty, value );
}
}
public class Parent : Base {
public static readonly DependencyProperty ChildProperty;
static Parent( ) {
ChildProperty = DependencyProperty.Register(
"Child", typeof( Child ), typeof( Parent ),
new PropertyMetadata( null as Child, _OnChildChanged ) );
void _OnChildChanged(
DependencyObject sender,
DependencyPropertyChangedEventArgs e ) =>
Console.WriteLine( "Child Changed!" );
}
public Parent( ) : base( ) =>
this.Child = new Child( );
public Child Child {
get => this.GetValue( ChildProperty ) as Child;
set => this.SetValue( ChildProperty, value );
}
protected override Freezable CreateInstanceCore( ) => new Parent( );
}
public class Child : Base {
public Child( ) : base( ) { }
protected override Freezable CreateInstanceCore( ) => new Child( );
}
}
重现:
- 创建 WPF 项目。目标 .Net 4.7.2.
- Select
App.xaml
- 在
Properties
下,将 Build Action
更改为 Page
- 将代码粘贴到
App.xaml.cs
。覆盖一切。
运行 这段代码,您应该会在控制台中看到消息打印两次。
为什么会这样?有办法阻止它发生吗?
跟进:
消息在控制台中打印了 2 次,因为 Child 属性 被设置了 2 次:
- Parent 构造函数中的第 1 次(this.Child = new Child();)
- 第二次调用时 p.Child.Trigger = new object( );
我认为在您的情况下,您可以在 _OnChildChanged() 中比较 Child 属性 的新值和旧值以防止出现问题:
void _OnChildChanged(
DependencyObject sender,
DependencyPropertyChangedEventArgs e)
{
if (e.NewValue != e.OldValue)
{
Console.WriteLine("Child Changed!");
}
}
此致!
在定义继承 Animatable
、class 的基础 class 时,我发现了一些奇怪的行为。
当我在 'Parent' class 中创建子 DependencyProperty 时,然后定义该 'Parent' class 的实例,然后更改 属性 parents child,我为 Parents Child 属性 定义的 PropertyChangedCallback 触发。
符合要求 Minimal, Complete and Verifiable Example:
using System;
using System.Collections.Generic;
using System.Windows;
using System.Windows.Media.Animation;
namespace MCVE {
/// <summary>
/// Interaction logic for App.xaml
/// </summary>
public partial class Program {
[STAThread]
public static int Main( ) {
Parent p = new Parent( );
p.Child.Trigger = new object( );
return 0;
}
}
public abstract class Base : Animatable {
public static readonly DependencyProperty TriggerProperty;
static Base( ) =>
TriggerProperty = DependencyProperty.Register(
"Trigger", typeof( object ), typeof( Base) );
public object Trigger {
get => this.GetValue( TriggerProperty );
set => this.SetValue( TriggerProperty, value );
}
}
public class Parent : Base {
public static readonly DependencyProperty ChildProperty;
static Parent( ) {
ChildProperty = DependencyProperty.Register(
"Child", typeof( Child ), typeof( Parent ),
new PropertyMetadata( null as Child, _OnChildChanged ) );
void _OnChildChanged(
DependencyObject sender,
DependencyPropertyChangedEventArgs e ) =>
Console.WriteLine( "Child Changed!" );
}
public Parent( ) : base( ) =>
this.Child = new Child( );
public Child Child {
get => this.GetValue( ChildProperty ) as Child;
set => this.SetValue( ChildProperty, value );
}
protected override Freezable CreateInstanceCore( ) => new Parent( );
}
public class Child : Base {
public Child( ) : base( ) { }
protected override Freezable CreateInstanceCore( ) => new Child( );
}
}
重现:
- 创建 WPF 项目。目标 .Net 4.7.2.
- Select
App.xaml
- 在
Properties
下,将Build Action
更改为Page
- 将代码粘贴到
App.xaml.cs
。覆盖一切。
运行 这段代码,您应该会在控制台中看到消息打印两次。
为什么会这样?有办法阻止它发生吗?
跟进
消息在控制台中打印了 2 次,因为 Child 属性 被设置了 2 次:
- Parent 构造函数中的第 1 次(this.Child = new Child();)
- 第二次调用时 p.Child.Trigger = new object( );
我认为在您的情况下,您可以在 _OnChildChanged() 中比较 Child 属性 的新值和旧值以防止出现问题:
void _OnChildChanged(
DependencyObject sender,
DependencyPropertyChangedEventArgs e)
{
if (e.NewValue != e.OldValue)
{
Console.WriteLine("Child Changed!");
}
}
此致!