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