共用方式為


逐步解說:使用 XAML 建立按鈕

此逐步解說的目標在於了解如何建立動畫按鈕,以透過 XAML 在 Windows Presentation Foundation (WPF) 應用程式內進行使用。 本逐步解說會使用樣式和範本來建立自訂按鈕資源,以從按鈕宣告中重新使用程式碼和按鈕邏輯分隔。 本逐步解說完全以 Extensible Application Markup Language (XAML) 撰寫。

重要

本逐步解說會引導您透過輸入或複製貼上 Extensible Application Markup Language (XAML) 至 Visual Studio,以完成建立應用程式的步驟。 如果您想要了解如何使用設計工具建立相同應用程式,請參閱使用透過 Microsoft Expression Blend 建立按鈕

下圖顯示 [已完成] 按鈕。

使用 XAML 建立的自訂按鈕

建立基本按鈕

我們先從建立新專案並新增按鈕至視窗開始。

若要建立新的 WPF 專案並新增按鈕至視窗

  1. 啟動 Visual Studio。

  2. 建立新 WPF 專案:在 [檔案] 功能表上,指向 [開新檔案],然後按一下 [專案]。 尋找 Windows 應用程式 (WPF) 範本,並將專案命名為「AnimatedButton」。 此操作會為應用程式建立基本架構。

  3. 新增基本預設按鈕:範本會提供此逐步解說所需的全部檔案。 在 [方案總管] 中按一下 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 資源

若要在按鈕上使用樣式以設定基本屬性

  1. 定義 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 資源

  2. 建立並使用樣式定義基本屬性值:將下列標記新增至 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 來執行應用程式,您會看到下列視窗。

    寬度為 90 且邊界為 10 的按鈕

    您可以使用樣式執行更多動作,包括各種方式來微調目標物件、指定複雜屬性值,甚至是使用樣式作為其他樣式的輸入。 如需詳細資訊,請參閱 設定樣式和範本

  3. 將樣式屬性值設定為資源: 資源可讓您使用簡單的方式重複使用常用定義的物件和值。 使用資源定義複雜的值讓程式碼更模組化,此方法特別實用。 新增下列反白顯示的標記至 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 執行應用程式。 它應該如下所示。

    具有漸層背景的按鈕

建立定義按鈕外觀的範本

在本節中,您會建立自訂按鈕外觀 (簡報) 的範本。 按鈕簡報是由數個物件所組成,包括矩形和其他元件,以提供按鈕獨特外觀。

到目前為止,應用程式中按鈕外觀的控制項僅限於變更按鈕屬性。 如果您想要對按鈕的外觀進行更明顯的變化,該怎麼做? 範本可讓您全面掌控物件簡報。 因為範本可以在樣式內使用,您可以將範本套用至樣式可套用的所有物件 (在此逐步解說中為按鈕)。

若要使用範本來定義按鈕外觀

  1. 設定範本: 因為如 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>
    
  2. 替代按鈕簡報:此時,您需要定義範本。 新增下列醒目顯示程式碼。 此標記會指定兩個具有圓邊的 Rectangle 元素,後面接著 DockPanelDockPanel 可用來主控按鈕的 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 執行應用程式。 它應該如下所示。

    具有 3 個按鈕的視窗

  3. 新增玻璃效果至範本: 接下來您將新增玻璃效果。 首先,您會建立建立玻璃漸層效果的資源。 在 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。

    使用 XAML 建立的自訂按鈕

建立按鈕互動

在本節中,您將建立屬性觸發程序和事件觸發程序來變更屬性值並執行動畫,以回應使用者動作,例如將滑鼠指標移至按鈕上並按一下。

新增互動 (滑鼠懸停、滑鼠離開、按一下等等) 的簡單方法是在範本或樣式中定義觸發程序。 若要建立 Trigger,您可以定義屬性「condition」,例如:按鈕 IsMouseOver 屬性值等於 true。 接著,您可以當定義觸發條件為 true 時所發生的 setter (動作)。

若要建立按鈕互動

  1. 新增範本觸發程序:將醒目顯示的標記新增至範本。

    <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>
    
  2. 新增屬性觸發程序:將醒目顯示的標記新增至 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 執行應用程式,並查看在按鈕上懸浮滑鼠指標時出現的效果。

  3. 新增焦點觸發程序:接下來,我們將新增一些相似 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 以執行應用程式,然後按一下其中一個按鈕。 請注意,當您按一下按鈕之後,按鈕會保持醒目顯示,因為其仍然保有焦點。 如果您按下另一個按鈕,新按鈕會取得焦點,而上一個按鈕會失去焦點。

  4. 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 元素的屬性 — DurationByDuration 指定動畫會在半秒後發生,By 指定玻璃效果縮小 10%。

    第二個事件觸發程觸發程序 (MouseLeave) 會停止第一個事件。 當您停止 Storyboard 時,所有動畫屬性都會回到其預設值。 因此,當使用者將指標從按鈕上移開時,按鈕會回到滑鼠指標移動至按鈕上方前的外觀。 如需動畫的詳細資訊,請參閱動畫概觀

  5. 按一下按鈕時新增的動畫:最後一個步驟是在使用者按一下按鈕時新增的觸發程序。 在 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 指向物件類型 (Button)。

  • 使用 Style 控制項整個應用程式中按鈕的基本屬性。

  • 已建立資源,例如用於 Style setter 的屬性值漸層。

  • 將範本套用至按鈕,以自訂整個應用程式中的按鈕外觀。

  • 為按鈕自訂行為,以回應包含動畫效果的使用者動作 (例如 MouseEnterMouseLeaveClick)。

另請參閱