如何根据 targetTypes 修改旧的命名样式以具有不同的设置器?

Posted

技术标签:

【中文标题】如何根据 targetTypes 修改旧的命名样式以具有不同的设置器?【英文标题】:How to modify legacy named style for having different setters based on targetTypes? 【发布时间】:2012-12-23 08:51:17 【问题描述】:

我有这个命名样式

<Style x:Key="validationSupport" TargetType="x:Type Control">
    <Setter Property="Margin" Value="5,2,14,2" />
    ...OMISSIS...
    <Style.Triggers>
        ...OMISSIS...
        <DataTrigger Binding="Binding DataContext.ActiveWorkspace.Editable, RelativeSource=RelativeSource  AncestorType=Window" Value="False">
            <Setter Property="IsEnabled" Value="False" />
        </DataTrigger>
    </Style.Triggers>

</Style>

我将它广泛用于 TextBoxes、ComboBoxes、DatePickers 等,因此我将所有这些元素的超类 Control 用作 TargetType。

现在我想使用“Control”没有的特定属性来区分 dataTrigger 内的设置器。似乎我必须创建具有不同名称的不同样式,每个样式都用于我想要区分的每个 targetType,但是这样我必须更改使用它的所有元素中的样式名称。有没有更聪明的方法来实现这个目标?我不想去修改我拥有的每个 xaml 文件。

第一次回答后更新

我尝试将以下设置器放入数据触发器中:

<Setter Property="Background" Value="#FFECECF8" />
<Setter Property="CheckBox.IsEnabled" Value="False" />
<Setter Property="DatePicker.IsEnabled" Value="False" />
<Setter Property="ComboBox.IsEnabled" Value="False" />
<Setter Property="TextBox.IsReadOnly" Value="True" /> 

不幸的是,测试结果很奇怪。 IsEnabled 属性也为 TextBoxes 设置,尽管前缀应将其应用程序限制为 CheckBoxes、DatePickers 和 ComboBoxes。

我的最终需要是使某些控件内容不可更改,以避免与禁用控件相关联的难以阅读的颜色。从以前的研究中,我了解到更改“禁用”控件的颜色并不是一件容易的事,并且涉及到控件模板的重新定义。所以我想应用 IsReadOnly 和 Background 的组合,但它不适用于上述问题。事实上,CheckBoxes、DatePickers 和 ComboBoxes 只能使用 IsEnabled 属性使其不可更改。 我错过了什么吗?

【问题讨论】:

【参考方案1】:

有办法,但我必须警告你 - 这远非最佳做法,应该避免

WPF 允许您使用所需的类型作为属性的前缀。这样,如果您将样式应用于不从前缀类型继承的控件 - 设置器将被忽略。

<Style x:Key="validationSupport" TargetType="x:Type Control">
    <Setter Property="Margin" Value="5,2,14,2" />
    ...OMISSIS...
    <Style.Triggers>
        ...OMISSIS...
        <DataTrigger Binding="Binding DataContext.ActiveWorkspace.Editable, RelativeSource=RelativeSource  AncestorType=Window" Value="False">
            <Setter Property="IsEnabled" Value="False" />
            <Setter Property="Button.Background" Value="Red" />
        </DataTrigger>
    </Style.Triggers>
</Style>

[对此进行广泛测试,因为我怀疑它可能会造成内存泄漏。]

【讨论】:

解决方案看起来很简单,我看不出有任何理由应该避免它。你能澄清这一点吗? 首先,您有一个针对目标类型 X 的样式,它在目标类型 Y 上执行操作。只要它只是一种样式,它是易于管理的,但是您很快就会发现自己在为其他样式和一对夫妇做几个月后,它变得一团糟(“为什么 ListBoxItem 上的边距会发生变化?!”)。其次,我不确定它不会泄漏内存——正如我所说,这需要测试。

以上是关于如何根据 targetTypes 修改旧的命名样式以具有不同的设置器?的主要内容,如果未能解决你的问题,请参考以下文章

您能否为一种 XAML 样式定义多个 TargetType?

将样式的 TargetType 属性设置为基类

无法覆盖由 TargetType 在单个特定控件上设置的全局 WPF 样式

样式 TargetType 在未附加到调试器时会导致 XamlParseException

WPF 自定义滚动条(ScrollViewScrollBar)样式

使用 DataTrigger 以样式绑定到 Self