• WPF 点击按钮时更改按钮样式界面效果的 XAML 实现方法


    在 WPF 中按钮 Button 将会吃掉路由事件,此时的 EventTrigger 如果通过 RoutedEvent 是 MouseLeftButtonDown 那么将会拿不到路由事件,也就触发不了,因此样式将不会变更。简单的解决方法就是通过 VisualStateManager 配合 VisualState 来实现

    实现效果如下,所有代码都是 XAML 代码

    实现方式为给 Button 定义一个样式,通过如下代码可以定义

    <Style TargetType="Button">
    </Style>
    

    上面代码没有定义样式资源的 key 因此会对容器内所有的 Button 按钮样式生效,因此我将这个样式放在需要使用的容器里面,这样才不会干扰其他容器内的元素

    <StackPanel>
        <StackPanel.Resources>
            <Style TargetType="Button"></Style>
        </StackPanel.Resources>
    </StackPanel>
    

    接着新建一个按钮,如下代码

    <StackPanel>
        <StackPanel.Resources>
            <Style TargetType="Button"></Style>
        </StackPanel.Resources>
        <Button Margin="10,10,10,10" Width="100" Height="100" Content="Button 1" HorizontalAlignment="Center"
                        VerticalAlignment="Center" />
    </StackPanel>
    

    接下来就是核心逻辑了,通过重写 Button 的 Template 内容,给内容的 Border 添加一些必要样式

    <Style TargetType="Button">
        <Setter Property="Template">
            <Setter.Value>
                <ControlTemplate TargetType="Button">
                    <Border x:Name="Border">
                        <Border.RenderTransform>
                            <ScaleTransform />
                        </Border.RenderTransform>
                        <Grid>
                            <Rectangle Fill="Blue"/>
                            <ContentPresenter HorizontalAlignment="Center" VerticalAlignment="Center" />
                        </Grid>
                    </Border>
                </ControlTemplate>
            </Setter.Value>
        </Setter>
    </Style>
    

    接着在 Border 添加 VisualStateManager 如下面代码

    <Border x:Name="Border">
        <Border.RenderTransform>
            <ScaleTransform />
        </Border.RenderTransform>
        <VisualStateManager.VisualStateGroups>
            <VisualStateGroup x:Name="CommonStates">
                <VisualState x:Name="Normal" />
                <VisualState x:Name="Pressed"/>
            </VisualStateGroup>
        </VisualStateManager.VisualStateGroups>
        <Grid>
            <Rectangle Fill="Blue"/>
            <ContentPresenter HorizontalAlignment="Center" VerticalAlignment="Center" />
        </Grid>
    </Border>
    

    可以看到上面代码有两个 VisualState 分别是 Normal 和 Pressed 两个,其中 Pressed 表示的是鼠标按下,因此可以通过在 Pressed 添加动画实现更改样式

    <VisualStateManager.VisualStateGroups>
        <VisualStateGroup x:Name="CommonStates">
            <VisualState x:Name="Normal" />
            <VisualState x:Name="Pressed">
                <Storyboard>
                    <DoubleAnimation Storyboard.TargetProperty="(RenderTransform).(ScaleTransform.ScaleX)"
                                     To="0.5" />
                    <DoubleAnimation Storyboard.TargetProperty="(RenderTransform).(ScaleTransform.ScaleY)"
                                     To="0.5" />
                </Storyboard>
            </VisualState>
        </VisualStateGroup>
    </VisualStateManager.VisualStateGroups>
    

    如上面代码是更改缩放

    那么抬起呢?其实抬起就是非 Pressed 也就是 Normal 状态,啥都不写将会自动还原为属性的值。原理是在依赖属性里面,其实属性是一个属性列表,将会取优先级最高的一个,而优先级是这样排序的

    属性系统强制
    
    活动动画或具有 Hold 行为的动画
    
    本地值
    
    TemplatedParent 模板属性
    
    隐式样式
    
    样式触发器
    
    模板触发器
    
    样式资源库
    
    默认(主题)样式
    
    继承
    
    来自依赖属性元数据的默认值
    

    详细请看 依赖项属性值优先级

    所有代码如下

            <StackPanel>
                <StackPanel.Resources>
                    <Style TargetType="Button">
                        <Setter Property="Template">
                            <Setter.Value>
                                <ControlTemplate TargetType="Button">
                                    <Border x:Name="Border">
                                        <Border.RenderTransform>
                                            <ScaleTransform />
                                        </Border.RenderTransform>
                                        <VisualStateManager.VisualStateGroups>
                                            <VisualStateGroup x:Name="CommonStates">
                                                <VisualState x:Name="Normal" />
                                                <VisualState x:Name="Pressed">
                                                    <Storyboard>
                                                        <DoubleAnimation
                                                            Storyboard.TargetProperty="(RenderTransform).(ScaleTransform.ScaleX)"
                                                            To="0.5" />
                                                        <DoubleAnimation
                                                            Storyboard.TargetProperty="(RenderTransform).(ScaleTransform.ScaleY)"
                                                            To="0.5" />
                                                    </Storyboard>
                                                </VisualState>
                                            </VisualStateGroup>
                                        </VisualStateManager.VisualStateGroups>
    
                                        <Grid>
                                            <Rectangle Fill="Blue"/>
                                            <ContentPresenter HorizontalAlignment="Center" VerticalAlignment="Center" />
                                        </Grid>
                                    </Border>
                                </ControlTemplate>
                            </Setter.Value>
                        </Setter>
                    </Style>
                </StackPanel.Resources>
    
                <Button Margin="10,10,10,10" Width="100" Height="100" Content="Button 1" HorizontalAlignment="Center"
                        VerticalAlignment="Center" />
            </StackPanel>
    
    

    代码放在 github 欢迎小伙伴访问

    当然,本文有很多知识点没有聊到,包括 Style 是什么,以及属性的配置应该如何写,还有动画 DoubleAnimation 是什么等等。我特别推荐小伙伴入门的时候看 微软技术教程 - 哔哩哔哩 ( ゜- ゜)つロ 乾杯~ Bilibili 的免费教程视频,包含了这些细节

  • 相关阅读:
    Git最佳实践
    Git学习笔记
    Error creating bean with name 'enableRedisKeyspaceNotificationsInitializer' defined in class path resource
    Python实现按着文件资源管理器里的顺序获取文件列表
    python excel接口自动化测试框架
    java进行屏幕截图
    Java启动桌面应用程序
    java自建一个获取当前电脑桌面的鼠标信息
    vue收集表单数据给后端交互
    vue路由懒加载(延迟加载)的写法..
  • 原文地址:https://www.cnblogs.com/lindexi/p/13657025.html
Copyright © 2020-2023  润新知