値を継承するカスタムの依存関係プロパティを作る方法

前回の投稿で「WPFと異なり値を継承する独自のカスタムプロパティを作ることは〜」と書きましたが、これまでWPFで値を継承する独自のカスタムプロパティを作る方法を紹介していませんでしたので、それを書きたいと思います。


MyStackPanel.vb

Public Class MyStackPanel
    Inherits StackPanel
 
    Public Property Test() As String
        Get
            Return GetValue(TestProperty)
        End Get
 
        Set(ByVal value As String)
            SetValue(TestProperty, value)
        End Set
    End Property
 
    Public Shared ReadOnly TestProperty As DependencyProperty = _
                        DependencyProperty.RegisterAttached("Test", _
                        GetType(String), GetType(MyStackPanel), _
                        New FrameworkPropertyMetadata("既定値", _
                        FrameworkPropertyMetadataOptions.Inherits))
 
End Class


MyButton.vb
Public Class MyButton
    Inherits Button
 
    Public Property Test() As String
        Get
            Return GetValue(TestProperty)
        End Get
 
        Set(ByVal value As String)
            SetValue(TestProperty, value)
        End Set
    End Property
 
    Public Shared ReadOnly TestProperty As DependencyProperty = _
                        MyStackPanel.TestProperty.AddOwner(GetType(MyButton), _
                        New FrameworkPropertyMetadata("既定値", _
                        FrameworkPropertyMetadataOptions.Inherits))
 
End Class


Window1.xamlWPF
<Window x:Class="Window1"
   xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
   xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
   xmlns:local="clr-namespace:DependencyPropertyValueInheritence"
   Title="Window1" Height="300" Width="300" FontSize="32">
    <local:MyStackPanel x:Name="myStackPanel" Test="継承値">
        <TextBlock Text="{Binding Path=Test, ElementName=myStackPanel}"/>
        <local:MyButton
                   Content="{Binding RelativeSource={x:Static RelativeSource.Self},
                   Path=Test}"/>
    </local:MyStackPanel>
</Window>





ポイントは2つです。


・親要素ではRegisterメソッドではなくRegisterAttachedメソッドを使って添付プロパティとして実装する。


下記のMSDNライブラリの記述には、Registerメソッドを使って通常の依存関係プロパティにした場合にはうまく動作しない場合があるというようなことが書かれています。

DependencyProperty.RegisterAttached メソッド (String, Type, Type, PropertyMetadata) (System.Windows)


値を継承する依存関係プロパティに RegisterAttached を使用する
Register の代わりに RegisterAttached を使用して依存関係プロパティを登録する 1 つのシナリオは、プロパティ値の継承をサポートすることです。依存関係プロパティを公開するプロパティラッパー アクセサをクラスが定義する場合や、Get* および Set* 静的メソッドを公開して、実際の添付プロパティのサポートアクセサを提供しない場合でも、RegisterAttached を使用して、値を継承する依存関係プロパティを登録する必要があります。プロパティ値の継承は、非添付依存関係プロパティのために機能しているように見えることがありますが、ランタイムツリーでの特定の要素の境界を介する非添付プロパティの継承動作は定義されていません。プロパティを添付として登録すると、添付プロパティは事実上プロパティ システムに対するグローバルプロパティとなり、プロパティ値の継承が確実に要素ツリーのすべての境界を介して機能するようになります。メタデータで Inherits を指定した場合は、必ず RegisterAttached を使用してプロパティを登録します。詳細については、「プロパティ値の継承」を参照してください。



・子要素はAddOwnerメソッドを使い所有者を追加する方法で実装する。