从DataTrigger内部更改样式

15

常常发生在WPF中,我可能走了错误的路,但我有以下情况:

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

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

这很合乎逻辑,但我想避免重复编写相同的设置器,只是因为我的触发条件改变了:

<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,从而允许我从内部更改样式?或者另一种方式:避免重复样式信息?


你想在两种不同的情况下应用相同的setter吗?请纠正我,我有不同的看法。改变样式是没有帮助的,因为一旦它被更改,它就会被还原。最后,你可以使用数据触发器来改变所需元素的父元素的样式中元素的样式。 - pushpraj
@pushpraj,是的,同样的设置器。我会尝试更新。 - Benjol
1个回答

22

以下是一个示例,演示如何基于数据触发器更改元素的样式:

<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是一个包装元素,它将在其控件模板中托管所需的元素。如果您希望按名称访问它,则需要将其放在控件模板中。一组数据触发器在控件模板的触发器中定义,这将根据需要在所需元素(按钮)上应用样式。

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

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

示例:

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

试一试,看看这是否有助于你实现所期望的结果。


3
勉强点了一个赞。这两种解决方案似乎都很丑陋,虽然我知道这不是你的错 :( - Benjol
有一种方法可以通过使用绑定到多值转换器来避免多个设置器。但我不确定它是否值得,因为语法变得非常冗长 :-/ - Mike

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接