控制初始化步骤混乱中的顺序

时间:2013-04-25 12:59:20

标签: wpf wpf-controls

我想知道在启动WPF应用程序时控件的初始化过程中究竟发生了什么?

DP什么时候会被初始化?绑定时? DataContext何时设置? DataContext是否在控件的构造函数中?有什么样的订单吗?

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

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

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

编辑:只是为了瑞秋。 dp接收值234并且immedialty回滚为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));

}

2 个答案:

答案 0 :(得分:1)

我发现DispatcherPriority Enum对于回忆确切的事件顺序很有用:

  • 发送
  • 正常 - 构造函数在此处运行
  • 的DataBind
  • 渲染
  • 加载
  • 背景
  • ContextIdle
  • ApplicationIdle
  • SystemIdle
  • 无效
  • 无效
  • 输入

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

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

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

您也可能会发现this SO answer有用:

  

创建并显示Window时的事件序列

     

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

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

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

  4.   
  5. 窗口和所有未折叠的Visuals都是Measured,这会导致每个Control上的ApplyTemplate,这会导致额外的   对象树构造包括更多构造函数和   getter / setter方法

  6.   
  7. 窗口及其上所有未折叠的视觉效果都是“已安排”

  8.   
  9. 窗口及其后代(逻辑和可视)接收Loaded事件

  10.   
  11. 重试首次设置失败的任何数据绑定

  12.   
  13. 窗口及其后代有机会直观地呈现其内容

  14.         

    创建Window时完成步骤1-2,无论是否为   所示。其他步骤通常直到Window才会发生   显示,但如果手动触发,它们可以更早发生。

根据添加到问题的代码进行修改

您的DependencyProperty.Register方法对我来说很有趣。该方法的签名与该方法的任何overloads都不匹配,并且您正在使用看似自定义的UIProperty类来设置默认值而不是正常{{3} }}

我可以确认,如果您的代码按正常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>

答案 1 :(得分: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"));
}