0
votes

I have a Control (ZlsUnitBrowserActive) with two DependencyProperties MaxWidthIdentifier/PropertiesDataTemplate. I'm stuck when try to bind these two properties in the Style:

System.Windows.Data Error: 4 : Cannot find source for binding with reference 'RelativeSource FindAncestor, AncestorType='PlcFramework.Zls.Production.ProductionControls.ZlsUnitBrowserActive', AncestorLevel='1''. BindingExpression:Path=PropertiesDataTemplate; DataItem=null; target element is 'DataGridTemplateColumn' (HashCode=30225241); target property is 'CellTemplate' (type 'DataTemplate')

<Style TargetType="productionControls:ZlsUnitBrowserActive">
    <Style.Setters>
        <Setter Property="Template">
            <Setter.Value>
                <ControlTemplate TargetType="productionControls:ZlsUnitBrowserActive">
                    <DataGrid>
                        <DataGrid.Columns>
                            <DataGridTemplateColumn>
                                <DataGridTemplateColumn.CellTemplate 
                                    MaxWidth="{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=productionControls:ZlsUnitBrowserActive}, Path=MaxWidthIdentifier}"
                                    CellTemplate="{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=productionControls:ZlsUnitBrowserActive}, Path=PropertiesDataTemplate}"/>
                            </DataGridTemplateColumn>
                        </DataGrid.Columns>
                    </DataGrid>
                </ControlTemplate>
            </Setter.Value>
        </Setter>
    </Style.Setters>
</Style>

Is there a special trick? Also tried by caching the ZlsUnitBrowserActive instance in DataGrid.Tag (see post: https://stackoverflow.com/a/3668699/6229375), without success.

2

2 Answers

1
votes

The reason why you can't bind a property of a DataGridColumn to a visual ancestor using a RelativeSource is that the column itself is not part of the visual tree so it has no ancestors to bind to.

The DataGrid control is part of the visual tree though and the "BindingProxy" can be used to bind to and "capture" a DataContext, for example using a RelativeSource of the DataGrid.

Thomas Levesque has written a blog post that explains this in detail: https://thomaslevesque.com/2011/03/21/wpf-how-to-bind-to-data-when-the-datacontext-is-not-inherited/.

0
votes

I found the solution. The trick is to use a "BindingProxy".

I didn't really understand exactly why I had to solve it this way. Maybe someone can give me an explanation or post a better solution. 😊

public class BindingProxy : Freezable
{
    public static readonly DependencyProperty DataProperty;

    static BindingProxy()
    {
        DataProperty = DependencyProperty.Register(nameof(Data), typeof(object), typeof(BindingProxy));
    }

    public object Data
    {
        get => GetValue(DataProperty);
        set => SetValue(DataProperty, value);
    }

    protected override Freezable CreateInstanceCore()
    {
        return new BindingProxy();
    }
}
<Style TargetType="productionControls:ZlsUnitBrowserActive">
    <Style.Setters>
        <Setter Property="Template">
            <Setter.Value>
                <ControlTemplate TargetType="productionControls:ZlsUnitBrowserActive">
                    <DataGrid>
                        <DataGrid.Resources>
                            <xamlHelper:BindingProxy x:Key="DataContextBindingProxy" Data="{Binding RelativeSource={RelativeSource TemplatedParent}}"/> 
                        </DataGrid.Resources>
                        <DataGrid.Columns>
                            <DataGridTemplateColumn>
                                <DataGridTemplateColumn.CellTemplate 
                                    MaxWidth="{Binding Path=Data.MaxWidthIdentifier, Source={StaticResource DataContextBindingProxy}}"
                                    CellTemplate="{Binding Path=Data.MaxWidthIdentifier, Source={StaticResource PropertiesDataTemplate}"/>
                            </DataGridTemplateColumn>
                        </DataGrid.Columns>
                    </DataGrid>
                </ControlTemplate>
            </Setter.Value>
        </Setter>
    </Style.Setters>
</Style>