代码之家  ›  专栏  ›  技术社区  ›  IFrank

基于另一种动画样式的WPF按钮样式

  •  0
  • IFrank  · 技术社区  · 1 年前

    我目前正在学习WPF动画。

    目前我有这种按钮样式:

    <Style TargetType="Button">
        <Setter Property="FontFamily" Value="{DynamicResource DefaultFont}" />
        <Setter Property="MinHeight" Value="{DynamicResource MinHeight}" />
        <Setter Property="Background" Value="{DynamicResource C4}" />
        <Setter Property="Template">
            <Setter.Value>
                <ControlTemplate TargetType="{x:Type Button}">
                    <Grid SnapsToDevicePixels="True">
                        <Border x:Name="Border" BorderThickness="0" CornerRadius="{DynamicResource Radius}" BorderBrush="{TemplateBinding BorderBrush}">
                            <Border.Background>
                                <SolidColorBrush x:Name="borderBackground" Color="{StaticResource Col5}" />
                            </Border.Background>
                            <ContentPresenter x:Name="Content" VerticalAlignment="Center" HorizontalAlignment="Center"  RecognizesAccessKey="True" />
                        </Border>
                    </Grid>
                    <ControlTemplate.Triggers>
                        <Trigger Property="IsMouseOver" Value="True">
                            <Setter Property="BorderBrush" TargetName="Border" Value="Black" />
                            <Trigger.EnterActions>
                                <BeginStoryboard x:Name="beginStoryboard">
                                    <Storyboard>
                                        <ColorAnimation Storyboard.TargetName="borderBackground"
                                                        Storyboard.TargetProperty="Color"
                                                        To="{StaticResource Col2}"
                                                        Duration="0:0:0.2">
                                        </ColorAnimation>
                                    </Storyboard>
                                </BeginStoryboard>
                            </Trigger.EnterActions>
                            <Trigger.ExitActions>
                                <RemoveStoryboard BeginStoryboardName="beginStoryboard" />
                                <BeginStoryboard x:Name="e">
                                    <Storyboard>
                                        <ColorAnimation Storyboard.TargetName="borderBackground"
                                                        Storyboard.TargetProperty="Color"
                                                        To="{StaticResource Col5}"
                                                        Duration="0:0:0.2">
                                        </ColorAnimation>
                                    </Storyboard>
                                </BeginStoryboard>
                            </Trigger.ExitActions>
                        </Trigger>
                    </ControlTemplate.Triggers>
                </ControlTemplate>
            </Setter.Value>
        </Setter>
        <Style.Resources>
            <Style TargetType="Border">
                <Setter Property="CornerRadius" Value="{DynamicResource Radius}" />
            </Style>
        </Style.Resources>
    </Style>
    

    正如你所看到的,这种风格应该做一些事情:

    • 应用默认值 FontFamily , MinHeight Background ;
    • 使用动画制作鼠标进入和鼠标离开效果 ColorAnimation 。颜色被定义为具有Col1、Col2等名称的资源。

    一切都正常工作(即使我怀疑这种风格可以用更精确的方式重写,但我需要指向正确的方向)。

    我的问题是:我需要在这个主要风格的基础上创建另一个风格,所以我写了这样的东西:

    <Style TargetType="Button" x:Key="AccentOnMouseOver" BasedOn="{StaticResource {x:Type Button}}">
        <Style.Triggers>
            <Trigger Property="IsMouseOver" Value="True">
                <Setter Property="BorderBrush" Value="DarkGreen"/>
                <Setter Property="BorderThickness" Value="1" />
            </Trigger>
        </Style.Triggers>
    </Style>
    

    不幸的是,这不起作用(应用了基本样式,但没有 BorderBrush 颜色 我如何编写带有背景的基本样式 颜色动画 然后从中派生出另一种风格,添加其他 Triggers ?

    一个解决方案是只复制和粘贴整个基本样式,添加一个x:Key并编辑我需要的属性,但我想要更干净的东西(这样,如果我更改动画部分,它将应用于所有衍生样式)。

    任何帮助都将不胜感激。

    0 回复  |  直到 1 年前
        1
  •  0
  •   EldHasp    1 年前

    主要的错误是对元素模板的逻辑及其与风格的相互作用的错误理解。

    1. 在您的示例中,主边界显示边界,但它有一个硬指定的值: <Border x:Name="Border" BorderThickness="0" 。至少,您需要将其更改为 <Border x:Name="Border" BorderThickness="{TemplateBinding BorderThickness}" .

    2. “鼠标悬停”状态的边框颜色在Template触发器中设置:

        <ControlTemplate.Triggers>
            <Trigger Property="IsMouseOver" Value="True">
                <Setter Property="BorderBrush" TargetName="Border" Value="Black" />
    

    因此,在这种状态下,与父元素属性的绑定将不再有效(其优先级低于模板触发器setter的优先级): <Border x:Name="Border" ... BorderBrush="{TemplateBinding BorderBrush}"> 因此,对于这种状态,为父元素的属性设置值是没有意义的。

    一次不能为一个属性设置多个值。因此,如果以后需要在使用元素的地方触发同一属性的更改,则应该想出某种机制来禁用模板中的触发器。

    解决。
    在任何情况下,您都必须创建自己的全新模板,因为此模板的逻辑不允许您根据需要使用元素。 在创建模板时,首先,您需要立即决定哪些元素、参数和值是常量,以及以后需要在使用元素的地方配置哪些。 自定义参数(如果它们不是父元素的属性)主要通过两种方式设置:动态资源键(DynamicResource)或AttachedProperty(例如-Material Design包)。