views:

664

answers:

5

How can I bind to a UserControl's property from within its ResourceDictionary? I want an object I declare in my resources to have the same DataContext as the UserControl it is contained in:

<UserControl
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="clr-namespace:Some.Namespace"
    DataContext="{Binding Path=ViewModel, RelativeSource={RelativeSource Self}}">
    <UserControl.Resources>
        <local:SomeClass
            x:Key="SomeClass"
            DataContext="{Binding Path=DataContext, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type UserControl}}}" />
    </UserControl.Resources>
</UserControl>

At runtime I get the error:

System.Windows.Data Error: 4 : Cannot find source for binding with reference 'RelativeSource FindAncestor, AncestorType='UserControl', AncestorLevel='1''. BindingExpression:Path=DataContext; DataItem=null; target element is 'SomeClass' (Name=''); target property is 'DataContext' (type 'Object')

A: 

I think what you're looking for is just {Binding} which binds to the inherited DataContext. Here's an example, though a bit strange shows how you can grab a color through binding to the DataContext:

<Window x:Class="AncestorBinding.Window1"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Title="Window1" Height="300" Width="300">
    <Window.Resources>
        <SolidColorBrush x:Key="MyBrush" Color="Blue" />
    </Window.Resources>
    <StackPanel>
        <Button DataContext="{Binding Source={StaticResource MyBrush}}" Content="My Button">
            <Button.Resources>
                <Style TargetType="{x:Type Button}">
                    <Setter Property="Background" Value="{Binding}" />
                </Style>
            </Button.Resources>
        </Button>
    </StackPanel>
</Window>
Mark Synowiec
Unfortunately {Binding} does not work for me--Cannot find element that provides DataContext. BindingExpression:(no path); DataItem=null; target element is 'SomeClass' (Name=''); target property is 'DataContext' (type 'Object')
emddudley
Have you tried not setting the DataContext at all? I would think your local:SomeClass would inherit the DataContext from the UserControl.
Mark Synowiec
I originally came across this problem because I did not set the DataContext at all: http://stackoverflow.com/questions/2073170
emddudley
A: 

What I would do is to create an attached behavior (ContextualizeResourceBehavior) on the user control, and specify the resource key on that attached behavior. The behavior would lookup the resource (not sure you would be able to do it on attach, if not you would need to hook up Loaded event) and transfer the data context.

Sergey Aldoukhov
A: 

when you add your resource to the visual tree it should inherit the data context. but... have a look at element spy it might just do what you need.

Aran Mulholland
+1  A: 

When using FindAncestor, the target element needs to be a descendent (either logical or visual) of the source. Your object does not appear in either the visual or logical tree, it's simply in the resources. So you can't use RelativeSource with FindAncestor for your object.

You can use ElementName in your Binding though. Something like this should work:

<UserControl x:Name="userControl"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="clr-namespace:Some.Namespace"
    DataContext="{Binding Path=ViewModel, RelativeSource={RelativeSource Self}}">
    <UserControl.Resources>
        <local:SomeClass
            x:Key="SomeClass"
            DataContext="{Binding Path=DataContext, ElementName=userControl}" />
    </UserControl.Resources>
</UserControl>
Tom Goff
This did not work for me. The binding could not find the element name using either x:Name or Name.
emddudley
A: 

My workaround was to set the DataContext of the resource in the code-behind.

.xaml

<local:SomeType x:Key="SomeKey" SomeProperty="{Binding ... }" />

.xaml.cs

public SomeControl()
{
    InitializeComponent();
    ((SomeType)this.Resources["SomeKey"]).DataContext = this;
}
emddudley