为什么要再次设置此 Animatable 属性?

Why is this Animatable property being set again?

跟进 个问题。

显然,出于某种原因,在明确设置 Parent.Child 属性(在构造函数内部或明确在构造函数外部)后,当我设置 Child.Trigger 属性 的 Parent.Child 对象,再次设置 Parent.Child 对象。这可以通过中断静态构造函数中定义的 _OnChildChanged 方法来观察。在调用它的第二个实例中,您可以看到 e.OldValue 不为空,并且它与 e.NewValue.

相同

为什么在设置 Trigger 属性 时再次设置 ParentChild 属性?

符合最低要求,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( );
    }
}

重现:

  1. 创建 WPF 项目。目标 .Net 4.7.2.
  2. Select App.xaml
  3. Properties 下,将 Build Action 更改为 Page
  4. 将代码粘贴到 App.xaml.cs。覆盖一切。

我查看了 Animatable class 的实现。它继承自 freezable class 继承自 DependencyObject class.

freezable 中,它覆盖了 DependencyObject 中的 OnPropertyChanged 事件并调用所有处理程序是对 Freezable 类型的变化依赖性 属性 的响应。

这意味着当 Child class 中的任何依赖值发生变化时,将调用 Freezable class 中的 OnPropertyChanged 事件。 FireChanged() 也调用了。在 FireChange() 方法中,它会调用 GetChangeHandlersAndInvalidateSubProperties 来检查子 class 的所有更改,然后 _OnChildChanged 将在其任何依赖项 属性 发生更改时被调用。

可以参考Freezable的源码class here


此行为也记录在 Freezable Objects Overview 部分 创建您自己的 Freezable Class (强调我的):

A class that derives from Freezable gains the following features.

  • Special states: a read-only (frozen) and a writable state.

  • Thread safety: a frozen Freezable can be shared across threads.

  • Detailed change notification: Unlike other DependencyObjects, Freezable objects provide change notifications when sub-property values change.

  • Easy cloning: the Freezable class has already implemented several methods that produce deep clones.