Question

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')

Was it helpful?

Solution

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;
}

OTHER TIPS

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>

Set x:Shared="False", this will clone resource on each use and make it a child of your element, enabling usage of bindings.

<local:SomeClass
            x:Key="SomeClass"
            x:Shared="False"
            DataContext="{Binding Path=DataContext, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type UserControl}}}" />

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>

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.

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.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top