user3978156
user3978156

Reputation:

TemplatedParent Binding in Resources of ControlTemplate

here is my scenario: I have a control template for a custom control which is rather big. To encapsulate the code of one of the features of that custom control, I'd like to introduce a helper class (called Internals). This class has logic code and provides some properties, which should be used in Bindings within the ControlTemplate.

Therefore I need to create an instance of this class in XAML and bind the TemplatedParent to a dependency property of the Internals class. My problem now is a concrete binding to the object the ControlTemplate is applied on. I've created a little proof of concept:

MainWindow.xaml:

<Window x:Class="WpfProofOfConcept.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:wpfProofOfConcept="clr-namespace:WpfProofOfConcept"
    xmlns:system="clr-namespace:System;assembly=mscorlib"
    Title="MainWindow" 
    Height="650" 
    Width="525">
<Window.Resources>
    <Style TargetType="Button">
        <Setter Property="Template">
            <Setter.Value>
                <ControlTemplate TargetType="Button">
                    <Grid>
                        <Grid.Resources>
                            <wpfProofOfConcept:Internals x:Key="InternalsKey"
                                                         Base="{Binding Path=., RelativeSource={RelativeSource TemplatedParent}}" />
                        </Grid.Resources>

                        <Grid.RenderTransform>
                            <RotateTransform Angle="20" />
                        </Grid.RenderTransform>

                        <!-- if uncommented, Binding to Base is working -->
                        <!--<wpfProofOfConcept:Internals Base="{Binding Path=., RelativeSource={RelativeSource TemplatedParent}}" />-->

                        <ContentPresenter Content="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=Content}"/>
                    </Grid>
                </ControlTemplate>
            </Setter.Value>
        </Setter> 
    </Style>
</Window.Resources>
<Grid>
    <Button>
        <TextBlock>Some text</TextBlock>
    </Button>
</Grid>
</Window>

Internals.cs:

public sealed class Internals : FrameworkElement
{
    public static readonly DependencyProperty BaseProperty =
        DependencyProperty.Register("Base", typeof(object), typeof(Internals), new PropertyMetadata((o, s) => { }));

    public object Base
    {
        get { return (object)GetValue(BaseProperty); }
        set { SetValue(BaseProperty, value); }
    }

    public Internals()
    {
    }
}

I need a reference to the concrete object the Template is applied on in my Internals object - thus the TemplatedParent binding. It does not work and I do not get any binding errors in the output.

The strange thing is that it works when the Internals object is created outside of the resources section (see commented lines in the XAML code). I do not

And one more thing thats keeps me confused: In Silverlight, binding to the TemplatedParent within a resource section works. This seems to be a WPF issue.

Do you have any ideas how to get this binding done? Or can you explain why TemplatedParent binding does not work in the resources section?

Thanks for all your hints!

Upvotes: 0

Views: 617

Answers (2)

user1182735
user1182735

Reputation: 764

It is possible to make Bindings from the Resources! But the object in resources has to be a freezable object, e.g. its class has to extend Freezable. For more information, have a look at this link from Dr. WPF http://drwpf.com/blog/2008/05/22/leveraging-freezables-to-provide-an-inheritance-context-for-bindings/:

In addition to the above scenario (where a freezable is set as a dependency property value on a dependency object), it is this enhanced notion of an inheritance tree and inheritance context that allows bindings on brushes, animations, and other freezable objects to work when those objects are placed within a resource dictionary.

You have to change the class implementation to:

public sealed class Internals : Freezable

Grüße,

Peter ;)

Upvotes: 0

Nitin Purohit
Nitin Purohit

Reputation: 18578

When you are creating Internals as Resource, it is not the part of the VisualTree and hence binding is not getting applied to it

Once your define it inside the Grid, it become the part of VisualTree.

Upvotes: 0

Related Questions