0

我想知道当我启动 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));

}
4

2 回答 2

1

我发现DispatcherPriority 枚举对于调用确切的事件顺序很有用:

  • 发送
  • 正常- 构造函数在这里运行
  • 数据绑定
  • 使成为
  • 已加载
  • 背景
  • 上下文空闲
  • 应用空闲
  • 系统空闲
  • 不活跃
  • 无效的
  • 输入

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

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

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

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

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

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

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

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

  3. 窗口及其上所有未折叠的视觉对象都是测量的,这会在每个控件上产生一个 ApplyTemplate,这会导致额外的对象树构造,包括更多的构造函数和 getter/setter

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

  5. 窗口及其后代(逻辑和视觉)接收到 Loaded 事件

  6. 任何在首次设置时失败的数据绑定都会重试

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

步骤 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>
于 2013-04-25T14:32:32.727 回答
0

在 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"));
}
于 2015-10-17T09:45:20.400 回答