0

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

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?

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?

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

}
Nick
  • 1,417
  • 1
  • 14
  • 21
snowy hedgehog
  • 652
  • 1
  • 7
  • 23

2 Answers2

1

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 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.

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.

You also might find this SO answer useful:

Sequence of events when a Window is created and shown

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

  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

  2. 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]

  3. 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

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

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

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

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

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.

Edit based on code added to question

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.

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

and the XAML is

<ContentControl x:Class="WpfApplication1.UserControl1"
                x:Name="TestPanel" ...>
    <Label Content="{Binding ElementName=TestPanel, Path=TestDependencyProperty}"/>
</ContentControl>
Community
  • 1
  • 1
Rachel
  • 130,264
  • 66
  • 304
  • 490
  • 1
    I am not sure how DispatcherPropery can help me with initalization steps of a control. I dont see the connection. – snowy hedgehog Apr 25 '13 at 15:39
  • 1
    @snowyguihedgehog It's not something you'd use to initialize a control, however I find the priority level list very useful to help remember what sequence the steps get executed in. In particular, the 4 I have in bold - Normal (Constructors), DataBinding, Rendering, and Loading. If you're having a problem with initializing a control, perhaps create a new question and include your code so we can take a look at it :) – Rachel Apr 25 '13 at 16:16
  • 1
    I am not having problems creating a control. I just want to know the order of initalization steps. How about you try to solve the problem of assigning value in constructor to a dp. It didnt work for me well as i described in question. – snowy hedgehog Apr 25 '13 at 18:47
  • @snowyguihedgehog Would you be able to edit your question to include the code for your DP property and how you are setting it? Your DP should get initialized first, then your constructor code run. I'm not sure I understand the problem you're having. – Rachel Apr 25 '13 at 18:51
  • 2
    @snowyguihedgehog See the update to my answer. The code runs the way I would expect it to, with the final result being "234", so I suspect the problem lies in either your custom code, or in how you're using/setting the property. – Rachel Apr 25 '13 at 19:46
  • @Rachel Now use OneWayToSource Binding. TestPanel.TestDependecyProperty="{Binding Path=SomeProp, Mode= OneWayToSource}" to a property in ViewModel. Can you pass 234 to the property in VM? – snowy hedgehog Apr 25 '13 at 20:43
  • @snowyguihedgehog Think of DPs as regular properties that can be set to point to another location to get their value. When you set your DP to a binding like your previous comment, you're *replacing* the existing "234" value with a binding. To set the value of a binding in code-behind, you need to get the binding and use `UpdateSource()`, like [this answer](http://stackoverflow.com/a/7990465/302677) shows. Note that my code sample only *gets* the DP and binds it to another property in the UI - your code sample would *set* it to a new value, which is a binding. – Rachel Apr 26 '13 at 11:26
  • Try using OneWayToSource and tell me what you got. – snowy hedgehog Apr 26 '13 at 12:00
  • 1
    @snowyguihedgehog Using `OneWayToSource` sets the value to `null` because it is a mode that tells the binding it should only send data from the target property to the source. Data binding occurs after the constructor runs, and `Label.Content` is `null`, so it is setting the DP to `null` when the data binding occurs, which is after the constructor runs. That is the expected behavior. – Rachel Apr 26 '13 at 12:24
  • 1
    Then set the content to 234 – snowy hedgehog Apr 26 '13 at 14:22
  • 2
    @snowyguihedgehog Setting `Label.Content = "234";` will replace the binding with a static value, so the DP will not get updated. You need to get the binding and update it's source if you want to set a bound value from code behind. If you're still having problems with your code, post your full code demonstrating the problem in your question (the DP, code-behind, and the XAML you're using) – Rachel Apr 26 '13 at 14:31
0

In WPF you are setting default values for DP with PropertyMetaData not via constructor.

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"));
}
Andrej B.
  • 170
  • 6