Почему это свойство Animatable устанавливается снова?
Продолжайте до этого вопроса.
Видимо, по какой-то причине после того, как Parent.Child
свойство (либо внутри конструктора, либо явно вне конструктора), когда я устанавливаю Child.Trigger
собственность Parent.Child
объект, Parent.Child
объект устанавливается еще раз. Это можно наблюдать, взломав _OnChildChanged
метод, определенный в статическом конструкторе. Во второй раз, когда он вызывается, вы можете видеть, что e.OldValue
не является нулевым, и что это так же, как e.NewValue
,
ПОЧЕМУ Child
собственностью Parent
устанавливается еще раз при настройке Trigger
имущество?
В соответствии с требуемым минимальным, полным и проверяемым примером:
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. Target .Net 4.7.2.
- Выбрать
App.xaml
- Под
Properties
, менятьBuild Action
вPage
- Вставьте код в
App.xaml.cs
, Перезаписать ВСЕ.
1 ответ
Я посмотрел на реализацию класса Animatable. Он наследуется от класса freezable, который наследуется от класса DependencyObject.
Внутри freezable он перезаписывает событие OnPropertyChanged из DependencyObject и вызывает все обработчики, которые являются ответом на изменяющееся свойство зависимости типа Freezable.
Это означает, что при изменении любого значения зависимости в дочернем классе будет вызвано событие OnPropertyChanged в классе Freezable. И вызвал также FireChanged(). Внутри метода FireChange() он будет вызывать GetChangeHandlersAndInvalidateSubProperties, чтобы проверить все изменения из подкласса, а затем _OnChildChanged будет вызываться всякий раз, когда изменяется любое его свойство зависимости.
Вы можете ссылаться на исходный код класса Freezable здесь
Это поведение также задокументировано в обзоре Freezable Objects, раздел Создание собственного класса Freezable (выделено мной):
Класс, производный от Freezable, получает следующие возможности.
Особые состояния: доступное только для чтения (замороженное) и доступное для записи состояние.
Безопасность потоков: замороженный Freezable может быть разделен между потоками.
Подробное уведомление об изменении: в отличие от других объектов DependencyObject, объекты Freezable предоставляют уведомления об изменениях при изменении значений под-свойств.
Простое клонирование: класс Freezable уже реализовал несколько методов, которые производят глубокие клоны.