【发布时间】: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,因此用户将能够添加他们想要的任何控件,因为这只是一个布局控件。它的开发是因为这是我们所有屏幕的布局方式,并且每个人都对其进行不同的编码,所以我想创建一个可以用来代替网格或堆栈面板的控件,并将实现布局和滑动绘制部分(万一这有什么不同)
标签: wpf templates controls datatemplate controltemplate