WPF 控件模板不根据依赖属性绑定值更改
Posted
技术标签:
【中文标题】WPF 控件模板不根据依赖属性绑定值更改【英文标题】:WPF Control Template Not Changing Based on Dependency Property Bound Value 【发布时间】:2021-08-26 18:06:30 【问题描述】:我的任务是创建一个新的布局控件,用于我们的 Windows 应用程序范围,应该有两种不同的布局;在特定 Windows 上显示哪一个将基于依赖属性。我从来没有做过类似的事情,但根据我的研究,似乎应该使用Control
。为了了解这一点,我尝试创建新的Control
,它将根据属性值显示TextBox
或Label
。我按类创建:
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>
但这也不起作用。任何有关如何使简单示例工作的建议/示例将不胜感激,因为除了我已经尝试过的建议之外,我找不到任何其他建议。提前谢谢你。
【问题讨论】:
为依赖属性实现 INotifyPropertyChanged 是没有意义的。他们确实已经提供了自己的通知机制。删除它,然后更新您的问题。 除此之外,Binding="Binding Overlay"
需要声明源对象:Binding="Binding Overlay, RelativeSource=RelativeSource Self"
。
@Clemens 我 99.99999% 确信 INotifyPropertyChanged 没有为此做任何事情,但我认真地尝试了一切,所以我想我会尝试一下。但是添加 RelativeSource 效果很好!非常感谢。
我这样做是为了尝试更改模板。在实际使用中,布局会更加复杂,包含标题部分、主体和滑动绘图,将具有ContentPresenter
,因此用户将能够添加他们想要的任何控件,因为这只是一个布局控件。它的开发是因为这是我们所有屏幕的布局方式,并且每个人都对其进行不同的编码,所以我想创建一个可以用来代替网格或堆栈面板的控件,并将实现布局和滑动绘制部分(万一这有什么不同)
【参考方案1】:
非常感谢 Clemens 帮助解决了这个问题。解决方案是将DataTrigger
中的绑定表达式从Binding=Binding Overlay
更改为Binding=Binding Overlay, RelativeSource=RelativeSource Self
。
【讨论】:
以上是关于WPF 控件模板不根据依赖属性绑定值更改的主要内容,如果未能解决你的问题,请参考以下文章