c# - 为什么要再次设置这个 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 项目。目标.Net 4.7.2。
- 选择
App.xaml
- 在 下
Properties
,更改Build Action
为Page
- 将代码粘贴到
App.xaml.cs
. 覆盖一切。
解决方案
我看了一下Animatable类的实现。它继承自可冻结类,该类继承自DependencyObject类。
在freezable内部,它覆盖了DependencyObject中的OnPropertyChanged事件并调用所有处理程序,这些处理程序响应于 Freezable 类型的不断变化的依赖项属性。
这意味着当 Child 类中的任何依赖值发生更改时,将调用 Freezable 类中的OnPropertyChanged事件。FireChanged () 也调用了。在FireChange()方法中,它将调用GetChangeHandlersAndInvalidateSubProperties来检查子类的所有更改,然后每当其依赖项属性发生更改时都会调用_OnChildChanged 。
您可以在此处参考 Freezable 类的源代码
此行为也记录在Freezable Objects Overview,部分创建您自己的 Freezable 类 (强调我的):
派生自 Freezable 的类具有以下特性。
特殊状态:只读(冻结)和可写状态。
线程安全:冻结的 Freezable 可以跨线程共享。
详细的更改通知:与其他 DependencyObjects 不同,Freezable 对象在子属性值更改时提供更改通知。
轻松克隆:Freezable 类已经实现了几种产生深度克隆的方法。
推荐阅读
- css - 仅使用 CSS 将元素列表显示为表格?
- xml - 查找 --httpPort 的 XPath
- java - 当 API 不应该是公共 API 时,在 AWS 上部署我的 REST API
- python - 允许稍后添加新课程的最佳实践?
- lighttpd - lighttpd 服务器错误 413 '请求太大'
- web - 检查网站是否具有 Open Graph 协议
- javascript - Nextjs Link 组件在不使用锚点的情况下是否对 SEO 友好?
- python - 如何抓取嵌套列表的字符串表示?
- kubernetes - "istio-init" 需要在其他 initContainers 之前运行
- vue.js - 没有 jQuery 的屏蔽输入 vuejs