我发现DispatcherPriority 枚举对于调用确切的事件顺序很有用:
- 发送
- 正常- 构造函数在这里运行
- 数据绑定
- 使成为
- 已加载
- 背景
- 上下文空闲
- 应用空闲
- 系统空闲
- 不活跃
- 无效的
- 输入
如您所见,构造函数首先运行,然后是数据绑定。
DependencyProperties
在创建对象时进行初始化,就像任何其他属性一样,因此这将在构造函数运行之前发生,因此该属性存在于构造函数中。
设置DataContext
属性或其他DependencyProperties
工作就像您设置的任何其他属性一样。如果您使用绑定设置它们,它们将在构造函数之后被评估。如果在 XAML 中设置它们,它们将在构造函数中设置。如果您在 Loaded 事件中设置它们,它们将在所有内容都被构造、绑定和渲染后被设置。
您也可能会发现这个 SO 答案很有用:
创建和显示窗口时的事件序列
根据要求,以下是创建和显示窗口时 WPF 中的主要事件序列:
在创建对象时调用构造函数和 getter/setter,包括正在更新的对象以及从它们继承的任何对象上的 PropertyChangedCallback、ValidationCallback 等
当每个元素被添加到可视化或逻辑树时,它的 Intialized 事件会被触发,这会导致除了您可以定义的任何特定于元素的初始化之外,还可以找到样式和触发器 [注意:不会为逻辑树中的叶子触发初始化事件如果根目录下没有 PresentationSource(例如 Window)]
窗口及其上所有未折叠的视觉对象都是测量的,这会在每个控件上产生一个 ApplyTemplate,这会导致额外的对象树构造,包括更多的构造函数和 getter/setter
窗口及其上所有未折叠的视觉对象均已排列
窗口及其后代(逻辑和视觉)接收到 Loaded 事件
任何在首次设置时失败的数据绑定都会重试
窗口及其后代有机会以视觉方式呈现其内容
步骤 1-2 在创建窗口时完成,无论它是否显示。其他步骤通常在显示窗口之前不会发生,但如果手动触发它们可以更早发生。
根据添加到问题的代码进行编辑
你的DependencyProperty.Register
方法在我看来很有趣。该方法的签名与该方法的任何重载都不匹配,并且您正在使用似乎是自定义UIProperty
类来设置默认值而不是普通的PropertyMetadata。
我可以确认,如果您的代码使用正常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>