WPF 控件模板不会根据依赖属性绑定值而改变

问题描述

我的任务是创建一个新的布局控件,用于我们的 Windows 应用程序范围内,应该有两种不同的布局;在特定 Windows 上显示一个将基于依赖项属性。我从来没有做过这样的事情,但根据我的研究,似乎应该使用 Control。为了了解这一点,我尝试创建新的 Control,它会根据属性显示 TextBoxLabel。我是按类创建的:

public class DetailsLayout : Control
{
    public static readonly DependencyProperty OverlayProperty =
            DependencyProperty.Register("Overlay",typeof(bool),typeof(DetailsLayout),new FrameworkPropertyMetadata(true));

    public bool Overlay
    {
        get { return (bool)GetValue(OverlayProperty); }
        set
        {
            OnPropertyChanged(nameof(Overlay));
            SetValue(OverlayProperty,value);
        }
    }

    static DetailsLayout()
    {
        DefaultStyleKeyProperty.OverrideMetadata(typeof(DetailsLayout),new FrameworkPropertyMetadata(typeof(DetailsLayout)));
    }

    public DetailsLayout()
    {
        DefaultStyleKey = typeof(DetailsLayout);
    }

MainWindow 我有

<layout:DetailsLayout Overlay="False">       
</layout:DetailsLayout>

对于测试,如果 Overlay = True 我想显示 TextBox,如果 Overlay = False 它应该显示标签。为了做到这一点,我尝试了几件事。首先,我尝试创建两个 ControlTemplate

<ControlTemplate x:Key="OverlayTemplate">
    <TextBox Text="This is the default (TRUE) layout (OVERLAY) with a textBox."/>
</ControlTemplate>

<ControlTemplate x:Key="PushTemplate">
    <Label Content="This is the optional (FALSE) layout (PUSH) with a label."/>
</ControlTemplate>

然后通过样式定义使用这些:

<Style targettype="{x:Type layout:DetailsLayout}">
    <Setter Property="Template">
       <Setter.Value>
            <ControlTemplate targettype="{x:Type layout:DetailsLayout}">
                <ContentControl Content="{Binding}">
                    <ContentControl.Style>
                        <Style targettype="ContentControl">
                            <Setter Property="Template" Value="{StaticResource OverlayTemplate}"/>
                            <Style.Triggers>
                                <DataTrigger Binding="{Binding Overlay,UpdateSourceTrigger=PropertyChanged}" Value="False">
                                    <Setter Property="Template" Value="{StaticResource PushTemplate}"/>
                                </DataTrigger>
                            </Style.Triggers>
                        </Style>
                    </ContentControl.Style>
                </ContentControl>
            </ControlTemplate>
        </Setter.Value>
    </Setter>
</Style>

我也尝试使用 DataTrigger's;一种具有认值,另一种同时指定了两个值:

两个值

<Style targettype="{x:Type layout:DetailsLayout}">
    <Style.Triggers>
        <DataTrigger Binding="{Binding Overlay}" Value="True">
            <Setter Property="Template">
                <Setter.Value>
                    <ControlTemplate targettype="{x:Type layout:DetailsLayout}">
                        <TextBox Text="This is the default (TRUE) layout (OVERLAY) with a textBox."/>
                    </ControlTemplate>
                </Setter.Value>
            </Setter>
        </DataTrigger>
        <DataTrigger Binding="{Binding Overlay}" Value="False">
            <Setter Property="Template">
                <Setter.Value>
                    <ControlTemplate targettype="{x:Type layout:DetailsLayout}">
                        <Label Content="This is the optional (FALSE) layout (PUSH) with a label."/>
                    </ControlTemplate>
                </Setter.Value>
            </Setter>
        </DataTrigger>
    </Style.Triggers>
</Style>

<Style targettype="{x:Type layout:DetailsLayout}">
    <Setter Property="Template">
        <Setter.Value>
            <ControlTemplate targettype="{x:Type layout:DetailsLayout}">
                 <TextBox Text="This is the default layout (OVERLAY) with a textBox."/>
            </ControlTemplate>
        </Setter.Value>
    </Setter>
    <Style.Triggers>
        <DataTrigger Binding="{Binding Overlay}" Value="False">
            <Setter Property="Template">
                <Setter.Value>
                    <ControlTemplate targettype="{x:Type layout:DetailsLayout}">
                        <Label Content="This is the optional layout (PUSH) with a label."/>
                    </ControlTemplate>
                </Setter.Value>
             </Setter>
        </DataTrigger>
    </Style.Triggers>
</Style>

目标只是在加载控件时选择正确的模板。因此,一个窗口可能使用 <layout:DetailsLayout Overlay="True" /> 之类的控件,另一个窗口将使用 <layout:DetailsLayout Overlay="False" />,并且在第一个窗口中将显示 TextBox,在第二个窗口中将显示 Label显示。但是一旦显示,它就不需要更改,因为 Overlay 值仅在 XAML 中指定(没有控件会在运行时更改此值)。

最后,我还尝试使用 DataTemplate 代替 ControlTemplate,如下所示:

<DataTemplate x:Key="OverlayTemplate">
    <TextBox Text="This is the default (TRUE) layout (OVERLAY) with a textBox."/>
</ControlTemplate>

<DataTemplate x:Key="PushTemplate">
    <Label Content="This is the optional (FALSE) layout (PUSH) with a label."/>
</ControlTemplate>

但这也不起作用。任何关于如何使简单示例工作的建议/示例将不胜感激,因为除了我已经尝试过的建议之外,我找不到任何其他建议。提前谢谢你。

解决方法

非常感谢 Clemens 帮助解决这个问题。解决方案是将 DataTrigger 中的绑定表达式从 Binding={Binding Overlay} 更改为 Binding={Binding Overlay,RelativeSource={RelativeSource Self}}