3
votes

I've made the smallest project I can to demonstrate the problem:

Code behind:

public partial class AxisControl : UserControl
{
    public static readonly DependencyProperty LayoutProperty =
        DependencyProperty.Register("Layout", typeof(Orientation), typeof(AxisControl),
            new PropertyMetadata(Orientation.Horizontal));

    public Orientation Layout
    {
        get { return (Orientation)GetValue(LayoutProperty); }
        set { SetValue(LayoutProperty, value); }
    }

    public AxisControl()
    {
        InitializeComponent();
    }
}

Xaml:

<UserControl.Resources>
    <ContentControl x:Key="horizontalLayout" Height="60">
        <TextBlock Text="{Binding Layout, RelativeSource={RelativeSource AncestorType=UserControl}}" HorizontalAlignment="Center" VerticalAlignment="Bottom"/>
    </ContentControl>
    <ContentControl x:Key="verticalLayout" Width="60">
        <TextBlock Text="{Binding Layout, RelativeSource={RelativeSource AncestorType=UserControl}}" HorizontalAlignment="Left" VerticalAlignment="Center">
            <TextBlock.LayoutTransform>
                <RotateTransform Angle="-90"/>
            </TextBlock.LayoutTransform>
        </TextBlock>
    </ContentControl>
</UserControl.Resources>
<UserControl.Style>
    <Style TargetType="UserControl">
        <Style.Setters>
            <Setter Property="Content" Value="{StaticResource horizontalLayout}"/>
        </Style.Setters>
        <Style.Triggers>
            <DataTrigger Binding="{Binding Layout, ElementName=root}" Value="Vertical">
                <Setter Property="Content" Value="{StaticResource verticalLayout}"/>
            </DataTrigger>
        </Style.Triggers>
    </Style>
</UserControl.Style>

Edit: Xaml now includes the elements I want to arrange in the UserControl.

MainWindow Xaml:

<Grid>
    <local:AxisControl Layout="Vertical"/>
</Grid>

The idea is to set the layout of the UserControl according to its Layout property so I put both layouts in static resources and made a Style to set the Content to the one I want according to Layout which is of type Orientation.

Edit: I want the Content to include elements arranged in a different order according to the Orientation.

The UserControl displays correctly but there's an error in the output window that concerns me:

Cannot find source for binding with reference 'RelativeSource FindAncestor, AncestorType='System.Windows.Controls.UserControl', AncestorLevel='1''. BindingExpression:Path=Layout; DataItem=null; target element is 'TextBlock' (Name=''); target property is 'Text' (type 'String')

Does this mean it's trying to do a Binding before it's in the visual tree possibly from the Trigger?

Note the use of RelativeSource and ElementName in the Bindings as it's incorrect to set the DataContext at the root of a UserControl because it breaks the DataContext inheritance.

What am I doing wrong and how can I get rid of the error?

1
It's unclear what exactly you are trying to achieve. Is the UserControl meant to contain a single TextBlock which is either rotated or not, depending on the Layout property (which should actually be named Orientation)? For what reason do you bind the Text properties of the TextBlock controls in the Resources to the Layout property?Clemens
One thing is for sure. You should not have different TextBlock resources for different layouts. Having UI elements as resources is usually a bad idea.Clemens
In the main program the UserControl is a ContentControl containing a TextBlock and in the code there is some rendering to display tickmarks. I bind the Text property to display something, the main program binds to a Title property.FreddyFlares

1 Answers

2
votes

Inspired by Clemens comment and further research I realized I needed a ControlTemplate resource for each layout and not resources containing instances of the elements themselves.

<UserControl.Resources>
    <ControlTemplate x:Key="horizontalLayout">
        <Border Height="60" Background="LightBlue">
            <TextBlock Text="{Binding Layout, RelativeSource={RelativeSource TemplatedParent}}" HorizontalAlignment="Center" VerticalAlignment="Bottom"/>
        </Border>
    </ControlTemplate>
    <ControlTemplate x:Key="verticalLayout" TargetType="UserControl">
        <Border Width="60" Background="LightBlue">
            <TextBlock Text="{Binding Layout, RelativeSource={RelativeSource TemplatedParent}}" HorizontalAlignment="Left" VerticalAlignment="Center">
                <TextBlock.LayoutTransform>
                    <RotateTransform Angle="-90"/>
                </TextBlock.LayoutTransform>
            </TextBlock>
        </Border>
    </ControlTemplate>
</UserControl.Resources>
<UserControl.Style>
    <Style TargetType="UserControl">
        <Style.Setters>
            <Setter Property="Template" Value="{StaticResource horizontalLayout}"/>
        </Style.Setters>
        <Style.Triggers>
            <DataTrigger Binding="{Binding Layout, ElementName=root}" Value="Vertical">
                <Setter Property="Template" Value="{StaticResource verticalLayout}"/>
            </DataTrigger>
        </Style.Triggers>
    </Style>
</UserControl.Style>

Layout = Horizontal

Layout = Orientation.Horizontal

Layout = Vertical

enter image description here