Search code examples
wpfattached-properties

Propagate an attached dependency property value to a template


Can an attached dependency property value be propagated to a templated children ?

Example : trying to propagate TagCloudService.* properties to the ItemTemplate

<ItemsControl x:Name="myItemsControl"
                pages:TagCloudService.MaximumFontSize="20"
                pages:TagCloudService.MaximumFontWeight="800"
                pages:TagCloudService.MinimumFontSize="10"
                pages:TagCloudService.MinimumFontWeight="400"
                pages:TagCloudService.NumberOfSizes="5"
                pages:TagCloudService.TagFrequency="{Binding Hotttnesss}"
                pages:TagCloudService.TagWeight="{Binding Weight}"
                Template="{StaticResource TagCloudItemsControlTemplate}">
    <ItemsControl.ItemTemplate>
        <StaticResource ResourceKey="TermTagCloudTemplate" />
    </ItemsControl.ItemTemplate>
</ItemsControl>

Here is the item template where some default values have been defined but should be overridden :

<DataTemplate x:Key="TermTagCloudTemplate" DataType="api:Term">
        <TextBlock Foreground="DodgerBlue"
                    Padding="10"
                    Style="{StaticResource TagCloudTextBlockStyle}"
                    Text="{Binding Name}"
                    pages:TagCloudService.MaximumFontSize="30"
                    pages:TagCloudService.MaximumFontWeight="800"
                    pages:TagCloudService.MinimumFontSize="20"
                    pages:TagCloudService.MinimumFontWeight="400"
                    pages:TagCloudService.NumberOfSizes="5"
                    pages:TagCloudService.TagFrequency="{Binding Frequency}"
                    pages:TagCloudService.TagWeight="{Binding Weight}">
        </TextBlock>
</DataTemplate>

I've tried to set FrameworkPropertyMetadataOptions.OverridesInheritanceBehavior instead of .Inherits, tried to comment the default values in the template but the properties are not propagated.

Is this possible or should I just create another ItemTemplate for that control ?


Solution

  • It's actually easy.

    Declare the attached property with Inherits-option:

    public static string GetFoo(DependencyObject obj)
    {
        return (string)obj.GetValue(FooProperty);
    }
    
    public static void SetFoo(DependencyObject obj, string value)
    {
        obj.SetValue(FooProperty, value);
    }
    
    public static readonly DependencyProperty FooProperty =
        DependencyProperty.RegisterAttached(
            "Foo", typeof(string), typeof(MainWindow),
            new FrameworkPropertyMetadata(
                   "default",
                   // this bit is important:
                   FrameworkPropertyMetadataOptions.Inherits));
    

    Test XAML:

    <Grid src:MainWindow.Foo="non-default">
        <TextBlock Text="{Binding (src:MainWindow.Foo),
                                  RelativeSource={RelativeSource Self}}"/>
    </Grid>
    

    shows "nondefault".

    This works across template boundary as well, full example follows.

    <Window x:Class="DPInheritance.MainWindow"
            xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
            xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
            xmlns:src="clr-namespace:DPInheritance"
            xmlns:sys="clr-namespace:System;assembly=mscorlib"
            Title="MainWindow" Height="350" Width="525">
        <Window.Resources>
            <DataTemplate x:Key="Test">
                <TextBlock Text="{Binding (src:MainWindow.Foo),
                                          RelativeSource={RelativeSource Self}}"/>
            </DataTemplate>
        </Window.Resources>
        <Grid src:MainWindow.Foo="non-default">
            <ItemsControl ItemTemplate="{StaticResource Test}">
                <sys:Int32>0</sys:Int32>
                <sys:Int32>1</sys:Int32>
                <sys:Int32>2</sys:Int32>
            </ItemsControl>
        </Grid>
    </Window>