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 的免費教程視頻,包含了這些細節


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM