wpf 从 DataTrigger 内部更改样式

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/25758592/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-13 12:30:44  来源:igfitidea点击:

Changing style from inside a DataTrigger

wpfxaml

提问by Benjol

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

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

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

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

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

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

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

<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...>

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?

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

回答by pushpraj

here is an example 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="secondry">
                        <Setter Property="Content" Value="Secondry 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 secondry}"/>
                    </DataTrigger>
                    <DataTrigger Binding="{Binding IsKeyboardFocusWithin,RelativeSource={RelativeSource Self}}" Value="true">
                        <Setter TargetName="button" Property="Style" Value="{StaticResource secondry}"/>
                    </DataTrigger>
                </ControlTemplate.Triggers>
            </ControlTemplate>
        </Control.Template>
    </Control>
    <Button Content="A normal button"/>
</StackPanel>

in this example Controlis a wrapper element which will host the desired element in it's 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.

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

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

我没有找到避免重复设置器的方法,也许交换/应用样式的能力可以帮助您实现相同的目标。

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

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

example

例子

<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="secondry">
                        <Setter Property="Content" Value="Secondry 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 secondry}"/>
                    </DataTrigger>
                    <DataTrigger Binding="{Binding IsKeyboardFocusWithin,RelativeSource={RelativeSource Self}}" Value="true">
                        <Setter Property="Tag" Value="{StaticResource secondry}"/>
                    </DataTrigger>
                </Style.Triggers>
            </Style>
        </Grid.Style>
    </Grid>
    <Button Content="A normal button"/>
</StackPanel>

try it and see if this help you to achieve the desired.

尝试一下,看看这是否有助于您实现所需。