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 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值