Wpf 控制初始化步骤的混沌序

Wpf 控制初始化步骤的混沌序,wpf,wpf-controls,Wpf,Wpf Controls,我想知道当我启动WPF应用程序时,控件初始化过程中到底发生了什么 DP何时初始化?什么时候装订?什么时候设置DataContext?控件的构造函数中是否有DataContext?有什么订单吗 我意识到我遇到了一个陷阱,一旦我在控件构造函数内的DP的getter/setter上设置了一个值,DP值就会被更新,但也会立即回滚到默认值null 所以我猜构造函数首先被初始化,然后是依赖属性 有人能帮我解决这个问题吗 编辑:只是为了瑞秋。dp接收值234,立即回滚到null。我认为这是因为构造函数首先被调

我想知道当我启动WPF应用程序时,控件初始化过程中到底发生了什么

DP何时初始化?什么时候装订?什么时候设置DataContext?控件的构造函数中是否有DataContext?有什么订单吗

我意识到我遇到了一个陷阱,一旦我在控件构造函数内的DP的getter/setter上设置了一个值,DP值就会被更新,但也会立即回滚到默认值null

所以我猜构造函数首先被初始化,然后是依赖属性

有人能帮我解决这个问题吗

编辑:只是为了瑞秋。dp接收值234,立即回滚到null。我认为这是因为构造函数首先被调用,然后dps的初始化发生,这将dp设置回null,因为null是默认值。我是不是想错了?控件或依赖项对象初始化步骤的顺序是什么

class MySuperDuperCoolClass : ContentControl
{
  public MySuperDuperCoolClass()
  {
    InitalizeComponents();
    this.MySuperDuperProperty = "234";
  }

  public string MySuperDuperProperty
  {
    get { return (string)GetValue(MySuperDuperPropertyProperty);}
    set { SetValue(MySuperDuperPropertyProperty, value);}
  }

  public static DependencyProperty MySuperDuperPropertyProperty =
    DependencyProperty.Register("MySuperDuperProperty", typeof(string), typeof(MySuperDuperCoolClass), 
    new PropertyMetadata(null));

}
我发现以下方法有助于回忆事件的确切顺序:

  • 发送
  • 正常-构造函数在此处运行
  • 数据绑定
  • 渲染
  • 已加载
  • 背景
  • 上下文空闲
  • 应用工具
  • 系统空闲
  • 不活跃
  • 无效的
  • 输入
如您所见,构造函数首先运行,然后是数据绑定

dependencProperties
在创建对象时进行初始化,就像任何其他属性一样,以便在运行构造函数之前进行初始化,从而使该属性存在于构造函数中

public partial class UserControl1 : ContentControl
{
    public UserControl1()
    {
        InitializeComponent();
    }

    public string TestDependencyProperty
    {
        get { return (string)GetValue(TestDependencyPropertyProperty); }
        set { SetValue(TestDependencyPropertyProperty, value); }
    }

    public static DependencyProperty TestDependencyPropertyProperty =
        DependencyProperty.Register("TestDependencyProperty", typeof(string), typeof(UserControl1), 
        new PropertyMetadata("234"));
}
设置
DataContext
属性或其他
dependencProperties
与您正在设置的任何其他属性一样工作。如果使用绑定对它们进行设置,它们将在构造函数之后进行计算。如果在XAML中设置它们,它们将在构造函数中设置。如果在Loaded事件中设置它们,则在构建、绑定和渲染所有内容之后,它们将被设置

您还可能会发现以下内容很有用:

创建和显示窗口时的事件序列

根据要求,以下是WPF中的主要事件顺序 将创建并显示以下窗口:

  • 构造函数和getter/setter在创建对象时被调用,对象包括上的PropertyChangedCallback、ValidationCallback等 正在更新的对象以及从中继承的任何对象

  • 当每个元素被添加到一个可视化或逻辑树中时,它的初始化事件被激发,这会导致样式和触发器被激活 发现应用于任何特定于元素的初始化之外 可以定义[注意:逻辑数据库中的叶未触发初始化事件] 如果根目录中没有PresentationSource(如窗口),则为树]

  • 对窗口及其上所有未折叠的视觉效果进行测量,这会在每个控件上产生一个ApplyTemplate,从而产生额外的 对象树构造,包括更多构造函数和 能手/二传手

  • 窗口及其上所有未折叠的视觉效果均已排列

  • 窗口及其子体(逻辑和视觉)接收加载的事件

  • 将重试首次设置失败的任何数据绑定

  • 该窗口及其子窗口有机会以可视方式呈现其内容

  • 步骤1-2在创建窗口时完成,无论是否 展示。其他步骤通常在窗口打开之前不会发生 如图所示,但如果手动触发,则可能更早发生

    根据添加到问题的代码进行编辑

    我觉得你的
    DependencyProperty.Register
    方法很有趣。该方法的签名与该方法的任何属性都不匹配,并且您正在使用似乎是自定义的
    UIProperty
    类来设置默认值,而不是正常值

    我可以确认,如果您的代码以正常的
    DependencyProperty.Register
    签名按预期运行,那么问题的可能原因可能是自定义代码中的某个地方,或者与您使用/设置属性的方式有关

    我用于快速样本测试的代码如下:

    public partial class UserControl1 : ContentControl
    {
        public UserControl1()
        {
            InitializeComponent();
            this.TestDependencyProperty = "234";
        }
    
        public string TestDependencyProperty
        {
            get { return (string)GetValue(TestDependencyPropertyProperty); }
            set { SetValue(TestDependencyPropertyProperty, value); }
        }
    
        public static DependencyProperty TestDependencyPropertyProperty =
            DependencyProperty.Register("TestDependencyProperty", typeof(string), typeof(UserControl1), 
            new PropertyMetadata(null));
    }
    
    而XAML是

    <ContentControl x:Class="WpfApplication1.UserControl1"
                    x:Name="TestPanel" ...>
        <Label Content="{Binding ElementName=TestPanel, Path=TestDependencyProperty}"/>
    </ContentControl>
    

    在WPF中,使用PropertyMetaData而不是通过构造函数为DP设置默认值

    public partial class UserControl1 : ContentControl
    {
        public UserControl1()
        {
            InitializeComponent();
        }
    
        public string TestDependencyProperty
        {
            get { return (string)GetValue(TestDependencyPropertyProperty); }
            set { SetValue(TestDependencyPropertyProperty, value); }
        }
    
        public static DependencyProperty TestDependencyPropertyProperty =
            DependencyProperty.Register("TestDependencyProperty", typeof(string), typeof(UserControl1), 
            new PropertyMetadata("234"));
    }
    

    我不确定DispatcherProperty如何帮助我初始化控件。我看不到这种联系。@snowyguihedgehog它不是用来初始化控件的东西,但是我发现优先级列表对于帮助记住执行步骤的顺序非常有用。特别是,我在粗体-普通(构造函数)、数据绑定、渲染和加载中使用了4种格式。如果您在初始化控件时遇到问题,可以创建一个新问题并包含代码,以便我们可以查看:)我在创建控件时没有遇到问题。我只想知道初始化步骤的顺序。如何尝试解决将构造函数中的值分配给dp的问题。“这对我来说并不像我在问题中描述的那样有效。”snowyguihedgehog看到了我答案的更新。代码按我预期的方式运行,最终结果为“234”,因此我怀疑问题在于您的自定义代码,或者您如何使用/设置属性。@snowyguihedgehog setting
    Label.Content=“234”
    将用静态值替换绑定,因此DP不会得到更新。如果要从代码隐藏中设置绑定值,则需要获取绑定并更新其源代码。如果您的代码仍然存在问题,请发布完整的代码来演示问题中的问题(DP、代码隐藏和您正在使用的XAML)