从 DataTrigger 内部更改样式 [英] Changing style from inside a DataTrigger

查看:29
本文介绍了从 DataTrigger 内部更改样式的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

正如 WPF 经常发生的那样,我可能会以错误的方式处理事情,但我有以下情况:

As often happens with WPF, I'm probably going about things the wrong way, but I have the following situation:

我想根据 DataTrigger 应用样式,但您不能从样式内部更改样式:

I would like to apply a style depending on a DataTrigger, but you can't change Style from inside a Style:

<Button>
   <Button.Style>
      <Style BasedOn="SomeStyle">
         <Style.Triggers>
            <DataTrigger ...>
               <Setter Property="Style" Value="OtherStyle" /> <---- NO CAN DO

确实是合乎逻辑的,但我想避免重复相同 setter,只是因为我的触发条件发生了变化:

Logical really, but what I want to avoid is duplication of the same setters, just because my trigger conditions change:

<Button>
   <Button.Style>
      <Style BasedOn="SomeStyle">
         <Style.Triggers>
            <DataTrigger Binding="{Binding X}" Value="Condition1">
               <Setter Property="A" Value="1" /> 
               <Setter Property="B" Value="1" /> 
               <etc...>
(...)

<Button>
   <Button.Style>
      <Style BasedOn="SomeStyle">
         <Style.Triggers>
            <DataTrigger Binding="{Binding X}" Value="Condition2">
               <Setter Property="A" Value="1" /> 
               <Setter Property="B" Value="1" /> 
               <etc...>

是否还有其他东西可以放置 DataTrigger,从而允许我从内部更改样式?或者另一种方式:避免重复样式信息?

Is there something else inside which I could put the DataTrigger, thus allowing me to change the style from inside it? Or another way of: avoiding duplicating style info?

推荐答案

以下示例说明了如何根据数据触发器更改元素的样式:

Here is an example of how you may change the style of an element based on the data trigger:

<StackPanel>
    <Control Focusable="False">
        <Control.Template>
            <ControlTemplate>
                <!--resources-->
                <ControlTemplate.Resources>
                    <Style TargetType="Button" x:Key="primary">
                        <Setter Property="Content" Value="Primary style"/>
                    </Style>
                    <Style TargetType="Button" x:Key="secondary">
                        <Setter Property="Content" Value="Secondary style"/>
                    </Style>
                </ControlTemplate.Resources>
                <!--content-->
                <Button Style="{StaticResource primary}" x:Name="button"/>
                <!--triggers-->
                <ControlTemplate.Triggers>
                    <DataTrigger Binding="{Binding IsMouseOver,RelativeSource={RelativeSource Self}}" Value="true">
                        <Setter TargetName="button" Property="Style" Value="{StaticResource secondary}"/>
                    </DataTrigger>
                    <DataTrigger Binding="{Binding IsKeyboardFocusWithin,RelativeSource={RelativeSource Self}}" Value="true">
                        <Setter TargetName="button" Property="Style" Value="{StaticResource secondary}"/>
                    </DataTrigger>
                </ControlTemplate.Triggers>
            </ControlTemplate>
        </Control.Template>
    </Control>
    <Button Content="A normal button"/>
</StackPanel>

在此示例中,Control 是一个包装元素,它将在其控件模板中承载所需的元素.如果您希望按名称访问它,则需要在控制模板中.控件模板的触发器中定义了一组数据触发器,它将根据需要将样式应用到所需元素(按钮)上.

In this example, Control is a wrapper element which will host the desired element in its control template. It is required to be in the control template if you wish to access it by name. A set of data triggers are defined in the control template's trigger, which will apply the style on the desired element (button) as needed.

我没有找到避免重复 setter 的方法.也许交换/应用样式的能力可以帮助您获得相同的结果.

I did not find a way to avoid duplicate setters. Perhaps the ability to swap/apply the style may help you achieve the same result.

如果您不想采用控件模板方法,您可以在元素中使用附加属性或未使用的 Tag 属性.在这个例子中,我们将利用两种方式绑定来实现相同的结果.

If you do not wish to go for the control template approach, you may make use of attached properties or an unused Tag property in the element. In this example, we will take advantage of two way binding to achieve the same result.

示例:

<StackPanel>
    <Grid>
        <!--content-->
        <Button Style="{Binding Tag,RelativeSource={RelativeSource FindAncestor,AncestorType=Grid}}"/>
        <Grid.Style>
            <Style TargetType="Grid">
                <!--resources-->
                <Style.Resources>
                    <Style TargetType="Button" x:Key="primary">
                        <Setter Property="Content" Value="Primary style"/>
                    </Style>
                    <Style TargetType="Button" x:Key="secondary">
                        <Setter Property="Content" Value="Secondary style"/>
                    </Style>
                </Style.Resources>
                <Setter Property="Tag" Value="{StaticResource primary}"/>
                <!--triggers-->
                <Style.Triggers>
                    <DataTrigger Binding="{Binding IsMouseOver,RelativeSource={RelativeSource Self}}" Value="true">
                        <Setter Property="Tag" Value="{StaticResource secondary}"/>
                    </DataTrigger>
                    <DataTrigger Binding="{Binding IsKeyboardFocusWithin,RelativeSource={RelativeSource Self}}" Value="true">
                        <Setter Property="Tag" Value="{StaticResource secondary}"/>
                    </DataTrigger>
                </Style.Triggers>
            </Style>
        </Grid.Style>
    </Grid>
    <Button Content="A normal button"/>
</StackPanel>

尝试一下,看看这是否有助于您达到预期的结果.

Try it and see if this helps you to achieve the desired result.

这篇关于从 DataTrigger 内部更改样式的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆