【问题标题】:Child object property change fires parents DependencyPropertyChanged callback?子对象属性更改触发父母 DependencyPropertyChanged 回调?
【发布时间】:2019-05-23 22:31:46
【问题描述】:

在定义继承 Animatable 类的基类时,我发现了一些奇怪的行为。

当我在“父”类中创建子 DependencyProperty,然后定义该“父”类的实例,然后更改父子的属性时,我为父子属性定义的 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( );
    }
}

复制:

  1. 创建 WPF 项目。目标 .Net 4.7.2。
  2. 选择App.xaml
  3. Properties 下,将Build Action 更改为Page
  4. 将代码粘贴到App.xaml.cs。覆盖所有内容。

运行此代码,您应该会在控制台中看到消息打印两次。

为什么会这样?有没有办法阻止它发生?

跟进Here:

【问题讨论】:

  • 嗨,我试图运行你的代码,它抛出 System.TypeInitializationException 异常作为这行代码:“ChildProperty = DependencyProperty.Register("Child", typeof(Child), typeof(Parent) , new PropertyMetadata(null as Child, _OnChildChanged));"
  • @NhanPhan 您将项目创建为控制台应用程序还是 WPF 应用程序。它需要是一个 WPF 应用程序。
  • 请注意,写null as Child 是多余的,原因有两个。首先,null 可以分配给每个引用类型,其次,PropertyMetadata 构造函数的默认值参数的类型是object
  • @Clemens 这很公平。这只是我自己的个人喜好,因为我有一些用于注册依赖属性的实用方法,一个期望 default 值,一个期望 PropertyMetaData,所以如果我没有通过 @ 明确提供属性类型,它往往会感到不安987654335@.

标签: c# wpf xaml dependency-properties dependencyobject


【解决方案1】:

消息在控制台打印 2 次,因为 Child 属性设置了 2 次:

  • 第一次在父构造函数中(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!");
                }
            }

问候!

【讨论】:

  • 太棒了。那么为什么在我没有明确这样做的情况下第二次设置属性?猜猜这需要进入一个新问题......
猜你喜欢
  • 1970-01-01
  • 2014-07-05
  • 1970-01-01
  • 2014-06-14
  • 2018-07-21
  • 1970-01-01
  • 2021-09-26
  • 1970-01-01
  • 2014-11-01
相关资源
最近更新 更多