DependencyProperty's value is null when method

2019-08-08 01:52发布

问题:

we have been working a complete day on this problem and have it all summed up to a small example. We are currently converting a project from Silverlight to WPF, in Silverlight both versions work, in WPF only one does.

We have a simple control with a string-type dependencyproperty like this:

public class MyControl : Control
{
  public String Text
  {
    get { return (String)GetValue(TextProperty); }
    set { SetValue(TextProperty, value); }
  }

  public static readonly DependencyProperty TextProperty =
    DependencyProperty.Register("Text", typeof(String), typeof(MyControl), new PropertyMetadata(null, TextChanged));

  private static void TextChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
  {

  }
}

Then we have a class with an attached property as follows:

public class MyAttachedProperty
{
  public static readonly DependencyProperty DescriptionProperty = DependencyProperty.RegisterAttached("Description", typeof(String), typeof(MyAttachedProperty), new PropertyMetadata(null, DescriptionPropertyChanged));

  public static String GetDescription(DependencyObject obj, String value)
  {
    return (String)obj.GetValue(DescriptionProperty);
  }

  public static void SetDescription(DependencyObject obj, String value)
  {
    obj.SetValue(DescriptionProperty, value);
  }

  private static void DescriptionPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
  {
    var MySuperbControl = d as MyControl;
    Debug.WriteLine("The control's text is: " + MySuperbControl.Text);
  }

  public static void DoNothing()
  {

  }
}

We implement our control like this in MainWindow.xaml:

<ContentControl x:Name="MyContentControl">
  <ContentControl.ContentTemplate>
    <DataTemplate>
      <local:MyControl x:Name="MyCntrl" Text="DefaultText" att:MyAttachedProperty.Description="Test"/>
    </DataTemplate>
  </ContentControl.ContentTemplate>
</ContentControl>

and in the code-behind have this constructor:

public MainWindow()
{
  MyAttachedProperty.DoNothing();
  InitializeComponent();
}

If you start the project this way, the Debug-text will not contain any text. If you call DoNothing() after InitializeComponent(), it will show the text. Can anyone please explain, why? Note, in Silverlight both ways work. Also, if you do not use the control in a datatemplate both ways work.

回答1:

It's interesting side effect. It makes sense when you think that DependencyProperty registration adds it to some global collection. If you call static constructor on MyAttachedProperty first it is added to the collection first and set first for an object.

If you force static constructor to run first on MyControl by adding same empty static method DoNothing then you can do

    public MainWindow()
    {
        MyControl.DoNothing();
        MyAttachedProperty.DoNothing();
        InitializeComponent();
    }

and the text will be shown or in case

    public MainWindow()
    {
        MyAttachedProperty.DoNothing();
        MyControl.DoNothing();
        InitializeComponent();
    }

the empty text will be shown.