逐步解說:使用 XAML 建立按鈕
此逐步解說的目標在於了解如何建立動畫按鈕,以透過 XAML 在 Windows Presentation Foundation (WPF) 應用程式內進行使用。 本逐步解說會使用樣式和範本來建立自訂按鈕資源,以從按鈕宣告中重新使用程式碼和按鈕邏輯分隔。 本逐步解說完全以 Extensible Application Markup Language (XAML) 撰寫。
重要
本逐步解說會引導您透過輸入或複製貼上 Extensible Application Markup Language (XAML) 至 Visual Studio,以完成建立應用程式的步驟。 如果您想要了解如何使用設計工具建立相同應用程式,請參閱使用透過 Microsoft Expression Blend 建立按鈕。
下圖顯示 [已完成] 按鈕。
建立基本按鈕
我們先從建立新專案並新增按鈕至視窗開始。
若要建立新的 WPF 專案並新增按鈕至視窗
啟動 Visual Studio。
建立新 WPF 專案:在 [檔案] 功能表上,指向 [開新檔案],然後按一下 [專案]。 尋找 Windows 應用程式 (WPF) 範本,並將專案命名為「AnimatedButton」。 此操作會為應用程式建立基本架構。
新增基本預設按鈕:範本會提供此逐步解說所需的全部檔案。 在 [方案總管] 中按一下 Window1.xaml 以開啟檔案。 根據預設,Window1.xaml 中有 Grid 元素。 移除 Grid 元素,並透過輸入或複製貼上下列醒目顯示的程式碼至 Window1.xaml,以新增幾個按鈕至 Extensible Application Markup Language (XAML) 頁面:
<Window x:Class="AnimatedButton.Window1" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Title="AnimatedButton" Height="300" Width="300" Background="Black"> <!-- Buttons arranged vertically inside a StackPanel. --> <StackPanel HorizontalAlignment="Left"> <Button>Button 1</Button> <Button>Button 2</Button> <Button>Button 3</Button> </StackPanel> </Window>
按下 F5 執行應用程式,藉此您應該會看到一組如下圖的按鈕。
現在已建立基本按鈕,您已完成在 Window1.xaml 檔案中的工作。 本逐步解說的其餘部分著重於 app.xaml 檔案,並定義按鈕的樣式和範本。
設定基本屬性
接下來,我們在這些按鈕上設定一些屬性,以控制按鈕外觀和版面配置。 相較於個別設定按鈕上的屬性,您會使用資源來定義整個應用程式的按鈕屬性。 應用程式資源在概念上與網頁的外部階層式樣式表 (CSS) 類似;不過,您在逐步解說的結尾會發現,相較於階層式樣式表 (CSS) 資源更為強大。 若要深入了解資源,請參閱 XAML 資源。
若要在按鈕上使用樣式以設定基本屬性
定義 Application.Resources 區塊:開啟 app.xaml,並在尚未開啟 app.xaml 時新增下列醒目顯示的標記:
<Application x:Class="AnimatedButton.App" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" StartupUri="Window1.xaml" > <Application.Resources> <!-- Resources for the entire application can be defined here. --> </Application.Resources> </Application>
資源範圍取決於您定義資源的位置。 在 app.xaml 檔案內
Application.Resources
中的定義資源,可讓資源在應用程式中的任何位置使用。 若要深入了解定義資源範圍,請參閱 XAML 資源。建立並使用樣式定義基本屬性值:將下列標記新增至
Application.Resources
區塊。 此標記會建立套用至應用程式中所有按鈕的 Style,並將按鈕的 Width 設定為 90,Margin 設定為 10:<Application.Resources> <Style TargetType="Button"> <Setter Property="Width" Value="90" /> <Setter Property="Margin" Value="10" /> </Style> </Application.Resources>
TargetType 屬性會指定樣式套用至類型 Button 的所有物件。 每個 Setter 都會為 Style 設定不同屬性值。 因此,此時應用程式中的每個按鈕寬度為 90,邊界為 10。 如果您按下 F5 來執行應用程式,您會看到下列視窗。
您可以使用樣式執行更多動作,包括各種方式來微調目標物件、指定複雜屬性值,甚至是使用樣式作為其他樣式的輸入。 如需詳細資訊,請參閱 設定樣式和範本。
將樣式屬性值設定為資源: 資源可讓您使用簡單的方式重複使用常用定義的物件和值。 使用資源定義複雜的值讓程式碼更模組化,此方法特別實用。 新增下列反白顯示的標記至 app.xaml。
<Application.Resources> <LinearGradientBrush x:Key="GrayBlueGradientBrush" StartPoint="0,0" EndPoint="1,1"> <GradientStop Color="DarkGray" Offset="0" /> <GradientStop Color="#CCCCFF" Offset="0.5" /> <GradientStop Color="DarkGray" Offset="1" /> </LinearGradientBrush> <Style TargetType="{x:Type Button}"> <Setter Property="Background" Value="{StaticResource GrayBlueGradientBrush}" /> <Setter Property="Width" Value="80" /> <Setter Property="Margin" Value="10" /> </Style> </Application.Resources>
在
Application.Resources
區塊正蝦方,您已建立名為「GrayBlueGradientBrush」的資源。 此資源會定義水平漸層。 此資源可用來作為應用程式中任何位置的屬性值,包括在 Background 屬性的按鈕樣式 setter 內部。 現在,所有按鈕都有這個漸層的 Background 屬性值。按 F5 執行應用程式。 它應該如下所示。
建立定義按鈕外觀的範本
在本節中,您會建立自訂按鈕外觀 (簡報) 的範本。 按鈕簡報是由數個物件所組成,包括矩形和其他元件,以提供按鈕獨特外觀。
到目前為止,應用程式中按鈕外觀的控制項僅限於變更按鈕屬性。 如果您想要對按鈕的外觀進行更明顯的變化,該怎麼做? 範本可讓您全面掌控物件簡報。 因為範本可以在樣式內使用,您可以將範本套用至樣式可套用的所有物件 (在此逐步解說中為按鈕)。
若要使用範本來定義按鈕外觀
設定範本: 因為如 Button 等控制項具有 Template 屬性,您可以使用 Setter 定義範本屬性值,就如同在 Style 中設定的其他屬性值一樣。 新增下列反白顯示的標記至您的按鈕樣式。
<Application.Resources> <LinearGradientBrush x:Key="GrayBlueGradientBrush" StartPoint="0,0" EndPoint="1,1"> <GradientStop Color="DarkGray" Offset="0" /> <GradientStop Color="#CCCCFF" Offset="0.5" /> <GradientStop Color="DarkGray" Offset="1" /> </LinearGradientBrush> <Style TargetType="{x:Type Button}"> <Setter Property="Background" Value="{StaticResource GrayBlueGradientBrush}" /> <Setter Property="Width" Value="80" /> <Setter Property="Margin" Value="10" /> <Setter Property="Template"> <Setter.Value> <!-- The button template is defined here. --> </Setter.Value> </Setter> </Style> </Application.Resources>
替代按鈕簡報:此時,您需要定義範本。 新增下列醒目顯示程式碼。 此標記會指定兩個具有圓邊的 Rectangle 元素,後面接著 DockPanel。 DockPanel 可用來主控按鈕的 ContentPresenter。 顯示按鈕內容的 ContentPresenter。 在本逐步解說中,內容為文字 (「Button 1」,「Button 2」,「Button 3」)。 所有範本元件 (矩形和 DockPanel) 的版面配置在 Grid 內。
<Setter.Value> <ControlTemplate TargetType="Button"> <Grid Width="{TemplateBinding Width}" Height="{TemplateBinding Height}" ClipToBounds="True"> <!-- Outer Rectangle with rounded corners. --> <Rectangle x:Name="outerRectangle" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Stroke="{TemplateBinding Background}" RadiusX="20" RadiusY="20" StrokeThickness="5" Fill="Transparent" /> <!-- Inner Rectangle with rounded corners. --> <Rectangle x:Name="innerRectangle" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Stroke="Transparent" StrokeThickness="20" Fill="{TemplateBinding Background}" RadiusX="20" RadiusY="20" /> <!-- Present Content (text) of the button. --> <DockPanel Name="myContentPresenterDockPanel"> <ContentPresenter x:Name="myContentPresenter" Margin="20" Content="{TemplateBinding Content}" TextBlock.Foreground="Black" /> </DockPanel> </Grid> </ControlTemplate> </Setter.Value>
按 F5 執行應用程式。 它應該如下所示。
新增玻璃效果至範本: 接下來您將新增玻璃效果。 首先,您會建立建立玻璃漸層效果的資源。 在
Application.Resources
區塊內的任何位置新增這些漸層資源:<Application.Resources> <GradientStopCollection x:Key="MyGlassGradientStopsResource"> <GradientStop Color="WhiteSmoke" Offset="0.2" /> <GradientStop Color="Transparent" Offset="0.4" /> <GradientStop Color="WhiteSmoke" Offset="0.5" /> <GradientStop Color="Transparent" Offset="0.75" /> <GradientStop Color="WhiteSmoke" Offset="0.9" /> <GradientStop Color="Transparent" Offset="1" /> </GradientStopCollection> <LinearGradientBrush x:Key="MyGlassBrushResource" StartPoint="0,0" EndPoint="1,1" Opacity="0.75" GradientStops="{StaticResource MyGlassGradientStopsResource}" /> <!-- Styles and other resources below here. -->
這些資源會作為插入按鈕範本 Grid 之矩形的 Fill。 新增下列反白顯示的標記至範本。
<Setter.Value> <ControlTemplate TargetType="{x:Type Button}"> <Grid Width="{TemplateBinding Width}" Height="{TemplateBinding Height}" ClipToBounds="True"> <!-- Outer Rectangle with rounded corners. --> <Rectangle x:Name="outerRectangle" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Stroke="{TemplateBinding Background}" RadiusX="20" RadiusY="20" StrokeThickness="5" Fill="Transparent" /> <!-- Inner Rectangle with rounded corners. --> <Rectangle x:Name="innerRectangle" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Stroke="Transparent" StrokeThickness="20" Fill="{TemplateBinding Background}" RadiusX="20" RadiusY="20" /> <!-- Glass Rectangle --> <Rectangle x:Name="glassCube" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" StrokeThickness="2" RadiusX="10" RadiusY="10" Opacity="0" Fill="{StaticResource MyGlassBrushResource}" RenderTransformOrigin="0.5,0.5"> <Rectangle.Stroke> <LinearGradientBrush StartPoint="0.5,0" EndPoint="0.5,1"> <LinearGradientBrush.GradientStops> <GradientStop Offset="0.0" Color="LightBlue" /> <GradientStop Offset="1.0" Color="Gray" /> </LinearGradientBrush.GradientStops> </LinearGradientBrush> </Rectangle.Stroke> <!-- These transforms have no effect as they are declared here. The reason the transforms are included is to be targets for animation (see later). --> <Rectangle.RenderTransform> <TransformGroup> <ScaleTransform /> <RotateTransform /> </TransformGroup> </Rectangle.RenderTransform> <!-- A BevelBitmapEffect is applied to give the button a "Beveled" look. --> <Rectangle.BitmapEffect> <BevelBitmapEffect /> </Rectangle.BitmapEffect> </Rectangle> <!-- Present Text of the button. --> <DockPanel Name="myContentPresenterDockPanel"> <ContentPresenter x:Name="myContentPresenter" Margin="20" Content="{TemplateBinding Content}" TextBlock.Foreground="Black" /> </DockPanel> </Grid> </ControlTemplate> </Setter.Value>
請注意,具有「glassCube」的
x:Name
屬性之矩形 Opacity 為 0,因此當您執行範例時,不會看到玻璃矩形覆蓋在頂端。 這是因為我們稍後會在使用者與按鈕互動時,將觸發程序新增至範本。 不過,您可以將 Opacity 值變更為 1 並執行應用程式,以查看按鈕現在的外觀。 請參閱下圖。 請在執行下一步之前,先變更 Opacity 至 0。
建立按鈕互動
在本節中,您將建立屬性觸發程序和事件觸發程序來變更屬性值並執行動畫,以回應使用者動作,例如將滑鼠指標移至按鈕上並按一下。
新增互動 (滑鼠懸停、滑鼠離開、按一下等等) 的簡單方法是在範本或樣式中定義觸發程序。 若要建立 Trigger,您可以定義屬性「condition」,例如:按鈕 IsMouseOver 屬性值等於 true
。 接著,您可以當定義觸發條件為 true 時所發生的 setter (動作)。
若要建立按鈕互動
新增範本觸發程序:將醒目顯示的標記新增至範本。
<Setter.Value> <ControlTemplate TargetType="{x:Type Button}"> <Grid Width="{TemplateBinding Width}" Height="{TemplateBinding Height}" ClipToBounds="True"> <!-- Outer Rectangle with rounded corners. --> <Rectangle x:Name="outerRectangle" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Stroke="{TemplateBinding Background}" RadiusX="20" RadiusY="20" StrokeThickness="5" Fill="Transparent" /> <!-- Inner Rectangle with rounded corners. --> <Rectangle x:Name="innerRectangle" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Stroke="Transparent" StrokeThickness="20" Fill="{TemplateBinding Background}" RadiusX="20" RadiusY="20" /> <!-- Glass Rectangle --> <Rectangle x:Name="glassCube" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" StrokeThickness="2" RadiusX="10" RadiusY="10" Opacity="0" Fill="{StaticResource MyGlassBrushResource}" RenderTransformOrigin="0.5,0.5"> <Rectangle.Stroke> <LinearGradientBrush StartPoint="0.5,0" EndPoint="0.5,1"> <LinearGradientBrush.GradientStops> <GradientStop Offset="0.0" Color="LightBlue" /> <GradientStop Offset="1.0" Color="Gray" /> </LinearGradientBrush.GradientStops> </LinearGradientBrush> </Rectangle.Stroke> <!-- These transforms have no effect as they are declared here. The reason the transforms are included is to be targets for animation (see later). --> <Rectangle.RenderTransform> <TransformGroup> <ScaleTransform /> <RotateTransform /> </TransformGroup> </Rectangle.RenderTransform> <!-- A BevelBitmapEffect is applied to give the button a "Beveled" look. --> <Rectangle.BitmapEffect> <BevelBitmapEffect /> </Rectangle.BitmapEffect> </Rectangle> <!-- Present Text of the button. --> <DockPanel Name="myContentPresenterDockPanel"> <ContentPresenter x:Name="myContentPresenter" Margin="20" Content="{TemplateBinding Content}" TextBlock.Foreground="Black" /> </DockPanel> </Grid> <ControlTemplate.Triggers> <!-- Set action triggers for the buttons and define what the button does in response to those triggers. --> </ControlTemplate.Triggers> </ControlTemplate> </Setter.Value>
新增屬性觸發程序:將醒目顯示的標記新增至
ControlTemplate.Triggers
區塊:<ControlTemplate.Triggers> <!-- Set properties when mouse pointer is over the button. --> <Trigger Property="IsMouseOver" Value="True"> <!-- Below are three property settings that occur when the condition is met (user mouses over button). --> <!-- Change the color of the outer rectangle when user mouses over it. --> <Setter Property ="Rectangle.Stroke" TargetName="outerRectangle" Value="{DynamicResource {x:Static SystemColors.HighlightBrushKey}}" /> <!-- Sets the glass opacity to 1, therefore, the glass "appears" when user mouses over it. --> <Setter Property="Rectangle.Opacity" Value="1" TargetName="glassCube" /> <!-- Makes the text slightly blurry as though you were looking at it through blurry glass. --> <Setter Property="ContentPresenter.BitmapEffect" TargetName="myContentPresenter"> <Setter.Value> <BlurBitmapEffect Radius="1" /> </Setter.Value> </Setter> </Trigger> <ControlTemplate.Triggers/>
按下 F5 執行應用程式,並查看在按鈕上懸浮滑鼠指標時出現的效果。
新增焦點觸發程序:接下來,我們將新增一些相似 setter 來處理按鈕具有焦點的情況 (例如,在使用者按一下按鈕後)。
<ControlTemplate.Triggers> <!-- Set properties when mouse pointer is over the button. --> <Trigger Property="IsMouseOver" Value="True"> <!-- Below are three property settings that occur when the condition is met (user mouses over button). --> <!-- Change the color of the outer rectangle when user mouses over it. --> <Setter Property ="Rectangle.Stroke" TargetName="outerRectangle" Value="{DynamicResource {x:Static SystemColors.HighlightBrushKey}}" /> <!-- Sets the glass opacity to 1, therefore, the glass "appears" when user mouses over it. --> <Setter Property="Rectangle.Opacity" Value="1" TargetName="glassCube" /> <!-- Makes the text slightly blurry as though you were looking at it through blurry glass. --> <Setter Property="ContentPresenter.BitmapEffect" TargetName="myContentPresenter"> <Setter.Value> <BlurBitmapEffect Radius="1" /> </Setter.Value> </Setter> </Trigger> <!-- Set properties when button has focus. --> <Trigger Property="IsFocused" Value="true"> <Setter Property="Rectangle.Opacity" Value="1" TargetName="glassCube" /> <Setter Property="Rectangle.Stroke" TargetName="outerRectangle" Value="{DynamicResource {x:Static SystemColors.HighlightBrushKey}}" /> <Setter Property="Rectangle.Opacity" Value="1" TargetName="glassCube" /> </Trigger> </ControlTemplate.Triggers>
按下 F5 以執行應用程式,然後按一下其中一個按鈕。 請注意,當您按一下按鈕之後,按鈕會保持醒目顯示,因為其仍然保有焦點。 如果您按下另一個按鈕,新按鈕會取得焦點,而上一個按鈕會失去焦點。
為 MouseEnter 和 MouseLeave 新增動畫:接下來,我們會將一些動畫新增至觸發程序。 在
ControlTemplate.Triggers
區塊內的任何位置新增下列標記。<!-- Animations that start when mouse enters and leaves button. --> <EventTrigger RoutedEvent="Mouse.MouseEnter"> <EventTrigger.Actions> <BeginStoryboard Name="mouseEnterBeginStoryboard"> <Storyboard> <!-- This animation makes the glass rectangle shrink in the X direction. --> <DoubleAnimation Storyboard.TargetName="glassCube" Storyboard.TargetProperty= "(Rectangle.RenderTransform).(TransformGroup.Children)[0].(ScaleTransform.ScaleX)" By="-0.1" Duration="0:0:0.5" /> <!-- This animation makes the glass rectangle shrink in the Y direction. --> <DoubleAnimation Storyboard.TargetName="glassCube" Storyboard.TargetProperty= "(Rectangle.RenderTransform).(TransformGroup.Children)[0].(ScaleTransform.ScaleY)" By="-0.1" Duration="0:0:0.5" /> </Storyboard> </BeginStoryboard> </EventTrigger.Actions> </EventTrigger> <EventTrigger RoutedEvent="Mouse.MouseLeave"> <EventTrigger.Actions> <!-- Stopping the storyboard sets all animated properties back to default. --> <StopStoryboard BeginStoryboardName="mouseEnterBeginStoryboard" /> </EventTrigger.Actions> </EventTrigger>
當滑鼠指標移動至按鈕上方時,玻璃效果矩形會縮小,當指標離開時會回到正常大小。
當指標移動至按鈕時,會觸發兩個動畫 (產生 MouseEnter 事件)。 這些動畫會沿著 X 和 Y 軸縮小玻璃矩形。 請注意 DoubleAnimation 元素的屬性 — Duration 和 By。 Duration 指定動畫會在半秒後發生,By 指定玻璃效果縮小 10%。
第二個事件觸發程觸發程序 (MouseLeave) 會停止第一個事件。 當您停止 Storyboard 時,所有動畫屬性都會回到其預設值。 因此,當使用者將指標從按鈕上移開時,按鈕會回到滑鼠指標移動至按鈕上方前的外觀。 如需動畫的詳細資訊,請參閱動畫概觀。
按一下按鈕時新增的動畫:最後一個步驟是在使用者按一下按鈕時新增的觸發程序。 在
ControlTemplate.Triggers
區塊內的任何位置新增下列標記:<!-- Animation fires when button is clicked, causing glass to spin. --> <EventTrigger RoutedEvent="Button.Click"> <EventTrigger.Actions> <BeginStoryboard> <Storyboard> <DoubleAnimation Storyboard.TargetName="glassCube" Storyboard.TargetProperty= "(Rectangle.RenderTransform).(TransformGroup.Children)[1].(RotateTransform.Angle)" By="360" Duration="0:0:0.5" /> </Storyboard> </BeginStoryboard> </EventTrigger.Actions> </EventTrigger>
按下 F5 以執行應用程式,然後按一下其中一個按鈕。 當您按一下按鈕時,玻璃矩形會旋轉。
摘要
在這個逐步解說中,您將執行下列練習:
使用 Style 控制項整個應用程式中按鈕的基本屬性。
已建立資源,例如用於 Style setter 的屬性值漸層。
將範本套用至按鈕,以自訂整個應用程式中的按鈕外觀。
為按鈕自訂行為,以回應包含動畫效果的使用者動作 (例如 MouseEnter、MouseLeave 和 Click)。