RunningCSharp

MS系開発者による、雑多な記事。記事は所属企業とは関係のない、個人の見解です。

WPF:プロパティ値の継承(包含継承)が可能な添付プロパティ

<Window x:Class="WpfApplication.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:WpfApplication"
        mc:Ignorable="d"
        Title="MainWindow" Height="350" Width="525">
    <GroupBox Header="test" Foreground="Red">
        <StackPanel Orientation="Vertical">
            <TextBlock Text="test" />
            <TextBox Text="test"/>
            <Button Content="test" />
        </StackPanel>
    </GroupBox>
</Window>

上記のようなxamlを実行した場合、GroupBoxのForegroundプロパティの値を子のアイテムが引き継ぐことがあります。 この動きを、プロパティの値の継承と呼びます。(クラスの派生による継承とは異なることから、「包含継承」と呼ぶことがあるようです。)

上記の例では、TextBlockはGroupBoxのForegroundを引き継ぎますが、TextBoxやButtonのForegroundは引き継がれないようです。

f:id:ys-soniclab:20160910215003p:plain

そこで、プロパティ値の継承が可能な添付プロパティを作成し、そのプロパティが設定されたコントロールのForegruondを強制的に書き換えるようにしてみます。

public class Att
{
    public static Brush GetForeground(DependencyObject obj)
    {
        return (Brush)obj.GetValue(ForegroundProperty);
    }

    public static void SetForeground(DependencyObject obj, Brush value)
    {
        obj.SetValue(ForegroundProperty, value);
    }

    public static readonly DependencyProperty ForegroundProperty =
        DependencyProperty.RegisterAttached("Foreground", typeof(Brush), typeof(Att), new FrameworkPropertyMetadata(null, OnForegroundChanged) { Inherits = true });

    private static void OnForegroundChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
    {
        var ctl = d as Control;
        if (ctl == null) return;
        ctl.Foreground = e.NewValue as Brush;
    }
}
<Window …>
    <GroupBox Header="test" local:Att.Foreground="Red">
        <StackPanel Orientation="Vertical">
            <TextBlock Text="test" />
            <TextBox Text="test"/>
            <Button Content="test" />
        </StackPanel>
    </GroupBox>
</Window>

上記の添付プロパティを付けると、Foregroundが強制的に変更されます。

f:id:ys-soniclab:20160910215020p:plain