控制初始化步骤混乱中的顺序 [英] Order In Chaos Of Control Initialization Steps

查看:23
本文介绍了控制初始化步骤混乱中的顺序的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I would like to know when is actually what happening inside initalization process of controls when I start a WPF application?

DP 什么时候初始化?什么时候绑定?DataContext 何时设置?DataContext 是否在控件的构造函数中可用?有什么顺序吗?

When are DP initalized? When Binding? When does DataContext get set? Is DataContext avaialbe in constructor of a control? Is there any kind of order?

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

I realized I ran into a trap that once I set a value on getter/setter of a DP inside constructor of a control the DP value gets updated but immediately also the values gets rolled back to default value which was null.

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

So my guess is that contructors get initalized first and then dependency properties.

有人可以帮我解决这个问题吗?

Can somebody help me out with this?

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

Just for Rachel. The dp receives the value 234 and immedialty rolls back to null. I think its because constructor gets called first and then subsequently the initalizing of dps happens which sets dp back to null because null is default value. Am i thinking wrong about this? What is the order of initalization steps of a control or dependency object.

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));

}

推荐答案

我找到了 DispatcherPriority Enum 用于回忆确切的事件顺序:

I find the DispatcherPriority Enum useful for recalling the exact event order:

  • 发送
  • 普通 - 构造函数在这里运行
  • 数据绑定
  • 渲染
  • 已加载
  • 背景
  • 上下文空闲
  • 应用程序空闲
  • 系统空闲
  • 无效
  • 无效
  • 输入
  • Send
  • Normal - Constructors run here
  • DataBind
  • Render
  • Loaded
  • Background
  • ContextIdle
  • ApplicationIdle
  • SystemIdle
  • Inactive
  • Invalid
  • Input

如您所见,构造函数首先运行,然后是数据绑定.

As you can see, Constructors get run first, followed by data bindings.

DependencyProperties 在创建对象时被初始化,就像任何其他属性一样,所以这会在运行构造函数之前发生,因此该属性存在于构造函数中.

DependencyProperties get initialized when the object gets created, just like any other property, so that would occur prior to the constructor being run so the property exists in the constructor.

设置 DataContext 属性或其他 DependencyProperties 就像您设置的任何其他属性一样工作.如果您使用绑定设置它们,它们将在构造函数之后进行评估.如果您在 XAML 中设置它们,它们将在构造函数中设置.如果您在 Loaded 事件中设置它们,它们将在所有内容构建、绑定和呈现后设置.

Setting the DataContext property or other DependencyProperties works just like any other property you are setting. If you set them with a binding, they'll get evaluated after the constructor. If you set them in the XAML, they'll get set in the Constructor. If you set them in the Loaded event, they'll get set after everything has been constructed, bound, and rendered.

您可能还会发现这个 SO 答案很有用:

You also might find this SO answer useful:

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

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

As requested, here is the sequence of major events in WPF when a window is created and shown:

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

  1. Constructors and getters/setters are called as objects are created, including PropertyChangedCallback, ValidationCallback, etc on the objects being updated and any objects that inherit from them

当每个元素被添加到可视化或逻辑树中时,它的 Intialized 事件被触发,这会导致样式和触发器被发现应用除了您的任何特定于元素的初始化之外可以定义 [注意:初始化事件不会为逻辑中的叶子触发如果根目录下没有 PresentationSource(例如 Window)]

As each element gets added to a visual or logical tree its Intialized event is fired, which causes Styles and Triggers to be found applied in addition to any element-specific initialization you may define [note: Initialized event not fired for leaves in a logical tree if there is no PresentationSource (eg Window) at its root]

窗口和其上所有未折叠的 Visuals 都是 Measured,这会在每个 Control 处产生一个 ApplyTemplate,从而导致额外的对象树构造,包括更多的构造函数和吸气剂/吸气剂

The window and all non-collapsed Visuals on it are Measured, which causes an ApplyTemplate at each Control, which causes additional object tree construction including more constructors and getters/setters

窗口及其上所有未折叠的视觉对象已排列

The window and all non-collapsed Visuals on it are Arranged

窗口及其后代(逻辑的和视觉的)接收到一个 Loaded 事件

The window and its descendants (both logical and visual) receive a Loaded event

重试第一次设置时失败的任何数据绑定

Any data bindings that failed when they were first set are retried

窗口及其后代有机会以视觉方式呈现其内容

The window and its descendants are given an opportunity to render their content visually

步骤 1-2 是在创建 Window 时完成的,无论是否显示.其他步骤通常不会在 Window 出现之前发生显示,但如果手动触发,它们可能会更早发生.

Steps 1-2 are done when the Window is created, whether or not it is shown. The other steps generally don't happen until a Window is shown, but they can happen earlier if triggered manually.

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

你的 DependencyProperty.Register 方法在我看来很有趣.该方法的签名与任何重载 用于该方法,并且您正在使用似乎是自定义的 UIProperty 类来设置默认值而不是正常的 PropertyMetadata.

Your DependencyProperty.Register method looks funny to me. The signature of the method doesn't match any of the overloads for that method, and you're using what appears to be a custom UIProperty class to set the default value instead of the normal PropertyMetadata.

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

I can confirm that if your code runs as expected with a normal DependencyProperty.Register signature, so the likely cause of your problem is either somewhere within your custom code, or its with how you are using/setting the property.

我用于快速示例测试的代码是这样的:

The code I used for a quick sample test is this:

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>

这篇关于控制初始化步骤混乱中的顺序的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆