wpf - addowner details, use and study

You might wonder what does the DependencyProperty.AddOwner do. in Zeeshan Amjad's blog - AddOwner functionality of Dependency Property in WPF he gaves some example. 

 

Ialso looked up the MSDN documentation - DependencyProperty.AddOwner Method (Type, PropertyMetadata);

 

 

msdn 写道

The return value of this method is used to declare and expose the dependency property, particularly as it exists on the adding owner class. Generally, the same property name for both original owner and added owner should be used to indicate the similar functionality. It is good practice to expose the identifiers, as well as new CLR property wrappers, for dependency properties that are added to types using AddOwner.

The AddOwner methodology recommended above is used when creating APIs declared within WPF. For instance, both Border and Controldefine a BorderBrush dependency property, which have similar functionality. Control defines its BorderBrush property to the property system by calling AddOwner on original owner Border and its registered BorderBrushProperty dependency property identifer. The AddOwnerreturn value is then used to establish a static DependencyProperty field (BorderBrushProperty)for that property on the added owner, and aBorderBrush property wrapper is also declared.

 

 

I wrote a test program.

 

 

namespace AddOwnerTest
{
  public class BaseControl : Control
  {

    public string MyDp
    {
      get { return (string)GetValue(MyDpProperty); }
      set { SetValue(MyDpProperty, value); }
    }

    // Using a DependencyProperty as the backing store for MyDp.  This enables animation, styling, binding, etc...
    public static readonly DependencyProperty MyDpProperty =
        DependencyProperty.Register("MyDp", typeof(string), typeof(BaseControl), new UIPropertyMetadata(string.Empty, new PropertyChangedCallback(BaseControlMyDpPropertyChangeCallback)));


    public static void BaseControlMyDpPropertyChangeCallback(DependencyObject dp, DependencyPropertyChangedEventArgs e)
    {
      // 
        Console.WriteLine("base Dependency Property change  d");
    }
  }
}

 

 

and Iwrote two Views, UserControl1, and UserControl2.

 

UserControl1.xaml.cs

 

 

 

namespace AddOwnerTest.Views
{
  /// <summary>
  /// Interaction logic for UserControl1.xaml
  /// </summary>
  public partial class UserControl1 : UserControl
  {
    public UserControl1()
    {
      InitializeComponent();
      MyDp = "1";
    }

    public static readonly DependencyProperty MyDpProperty;

    public string MyDp
    {
      get { return (string)GetValue(MyDpProperty); }
      set { SetValue(MyDpProperty, value); }
    }

    static UserControl1()
    {
      UserControl1.MyDpProperty = BaseControl.MyDpProperty.AddOwner(typeof(UserControl1), new PropertyMetadata(string.Empty, new PropertyChangedCallback(MyDpUserControl1ChangedCalback)));
    }

    public static void MyDpUserControl1ChangedCalback(DependencyObject dp, DependencyPropertyChangedEventArgs e)
    {
      // 
      Console.WriteLine("MyDpProperty changed in UserControl1");
    }
  }
}

 

 

and the UserControl1.xaml 

 

 

 

<UserControl x:Class="AddOwnerTest.Views.UserControl1"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
             xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
             mc:Ignorable="d" 
             d:DesignHeight="300" d:DesignWidth="300"
             >
    <WrapPanel >
        <TextBlock Text="User Control 1:" />
        <TextBox Text="{Binding Path=MyDp, Mode=TwoWay,RelativeSource={RelativeSource Mode=FindAncestor, AncestorLevel=2,AncestorType=UserControl}}" />
    </WrapPanel>
</UserControl>
 

Similarly, the code of UserControl2.xaml.cs

 

 

namespace AddOwnerTest.Views
{
  /// <summary>
  /// Interaction logic for UserControl2.xaml
  /// </summary>
  public partial class UserControl2 : UserControl
  {
    public UserControl2()
    {
      InitializeComponent();
    }

    public static readonly DependencyProperty MyDpProperty;

    public string MyDp
    {
      get { return (string)GetValue(MyDpProperty); }
      set { SetValue(MyDpProperty, value); }
    }

    static UserControl2()
    {
      UserControl2.MyDpProperty = BaseControl.MyDpProperty.AddOwner(typeof(UserControl2), new PropertyMetadata(string.Empty, new PropertyChangedCallback(MyDpUserControl2ChangedCalback)));
    }

    public static void MyDpUserControl2ChangedCalback(DependencyObject dp, DependencyPropertyChangedEventArgs e)
    {
      // 
      Console.WriteLine("MyDpProperty changed in UserControl2");
    }
  }
}

 

and the UserControl2.xaml

 

namespace AddOwnerTest.Views
{
  /// <summary>
  /// Interaction logic for UserControl2.xaml
  /// </summary>
  public partial class UserControl2 : UserControl
  {
    public UserControl2()
    {
      InitializeComponent();
    }

    public static readonly DependencyProperty MyDpProperty;

    public string MyDp
    {
      get { return (string)GetValue(MyDpProperty); }
      set { SetValue(MyDpProperty, value); }
    }

    static UserControl2()
    {
      UserControl2.MyDpProperty = BaseControl.MyDpProperty.AddOwner(typeof(UserControl2), new PropertyMetadata(string.Empty, new PropertyChangedCallback(MyDpUserControl2ChangedCalback)));
    }

    public static void MyDpUserControl2ChangedCalback(DependencyObject dp, DependencyPropertyChangedEventArgs e)
    {
      // 
      Console.WriteLine("MyDpProperty changed in UserControl2");
    }
  }
}
 

 

Last, is the MainWindow.xaml file 

 

<Window x:Class="AddOwnerTest.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="MainWindow" Height="350" Width="525"
        xmlns:local="clr-namespace:AddOwnerTest"
        xmlns:views="clr-namespace:AddOwnerTest.Views"
        >
    <Window.Resources>
        <local:BaseControl x:Key="BaseControl"/>
    </Window.Resources>
    <StackPanel>
        <views:UserControl1 />
        <views:UserControl2 />
        <!--<TextBox Text="{Binding Path=Parent.Children[0].MyDp, Mode=TwoWay, RelativeSource={RelativeSource Self}}" />-->
        <TextBox Text="{Binding Path=MyDp, Mode=TwoWay, Source={StaticResource BaseControl}}" />
    </StackPanel>
</Window>
 

You won't see result is quite contrary to the hypothesis.

 

 

 

 

    // this is to test the add owner call from the DependnecyProperty class.
    // ideally, if you add an owner to a existing DependencyProperty, then  
    // the newly added owner should be notified if the underlying data updates.
    //
    // the test is to create two views, and they both are added as an owner to an 
    // DP that is declared in a base class
    // Then we try to update the base class' DP (by updating the model behind), and we are going to see if 
    // two views's displa is updated.
    // 

 

 

This is because addOwner create a new metadata under the DependencyProperty for the adding class.  And it does not create some new DependecyProperty or what so ever.

 

 

So, in a nutshell, the AddOwner register a new MetaData for the adding classes. It is used to decrease the duplication on register a new DependencyProperty.

 

Also, with sharing the same DependencyProperty, you can pass different DependencyObject to get the Metadata tha is assiciated with the Type/DO..

 

 

 

See more on the Dependency Property Metadata 

你可能感兴趣的:(WPF)