コントロールのためのテンプレートを作成するCreate a template for a control

Windows Presentation Foundation (WPF) を使用すると、独自の再利用可能なテンプレートを使用して、既存のコントロールの視覚的な構造と動作をカスタマイズできます。With Windows Presentation Foundation (WPF), you can customize an existing control's visual structure and behavior with your own reusable template. テンプレートは、アプリケーション、ウィンドウ、ページにグローバルに適用することも、コントロールに直接適用することもできます。Templates can be applied globally to your application, windows and pages, or directly to controls. 新しいコントロールを作成する必要があるほとんどのシナリオは、代わりに既存のコントロール用の新しいテンプレートを作成することによってカバーできます。Most scenarios that require you to create a new control can be covered by instead creating a new template for an existing control.

重要

デスクトップ ガイド ドキュメントは作成中です。The Desktop Guide documentation is under construction.

この記事では、Button コントロールの新しい ControlTemplate を作成する方法について説明します。In this article, you'll explore creating a new ControlTemplate for the Button control.

ControlTemplate を作成するタイミングWhen to create a ControlTemplate

コントロールには、BackgroundForegroundFontFamily などの多くのプロパティがあります。Controls have many properties, such as Background, Foreground, and FontFamily. これらのプロパティは、コントロールの外観のさまざまな側面を制御しますが、これらのプロパティを設定することによって行うことができる変更は制限されます。These properties control different aspects of the control's appearance, but the changes that you can make by setting these properties are limited. たとえば、CheckBox では、Foreground プロパティを青に、FontStyle を斜体に設定できます。For example, you can set the Foreground property to blue and FontStyle to italic on a CheckBox. コントロールの他のプロパティを設定するだけでは、必要な外見のカスタマイズが十分にできない場合は、ControlTemplate を作成します。When you want to customize the control's appearance beyond what setting the other properties on the control can do, you create a ControlTemplate.

ほとんどのユーザー インターフェイスのボタンの外観はテキストが記載されている四角形で、基本的には同じです。In most user interfaces, a button has the same general appearance: a rectangle with some text. 丸いボタンを作成する場合は、ボタンを継承する新しいコントロールを作成するか、ボタンの機能を再作成します。If you wanted to create a rounded button, you could create a new control that inherits from the button or recreates the functionality of the button. さらに、新しいユーザー コントロールによって、円形のビジュアルを指定できます。In addition, the new user control would provide the circular visual.

新しいコントロールを作成しないようにするには、既存のコントロールの視覚的なレイアウトをカスタマイズします。You can avoid creating new controls by customizing the visual layout of an existing control. 丸いボタンを使用して、目的の視覚的なレイアウトで ControlTemplate を作成します。With a rounded button, you create a ControlTemplate with the desired visual layout.

一方、新しい機能、異なるプロパティ、および新しい設定を持つコントロールが必要な場合は、新しい UserControl を作成します。On the other hand, if you need a control with new functionality, different properties, and new settings, you would create a new UserControl.

必須コンポーネントPrerequisites

新しい WPF アプリケーションを作成し、MainWindow.xaml (または任意の別のウィンドウ) の <Window> 要素で次のプロパティを設定します。Create a new WPF application and in MainWindow.xaml (or another window of your choice) set the following properties on the <Window> element:

Title Template Intro Sample
SizeToContent WidthAndHeight
MinWidth 250

<Window> 要素のコンテンツを次の XAML に設定します。Set the content of the <Window> element to the following XAML:

<StackPanel Margin="10">
    <Label>Unstyled Button</Label>
    <Button>Button 1</Button>
    <Label>Rounded Button</Label>
    <Button>Button 2</Button>
</StackPanel>

最終的に、MainWindow.xaml ファイルは次のようになります。In the end, the MainWindow.xaml file should look similar to the following:

<Window x:Class="IntroToStylingAndTemplating.Window1"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:IntroToStylingAndTemplating"
        mc:Ignorable="d"
        Title="Template Intro Sample" SizeToContent="WidthAndHeight" MinWidth="250">
    <StackPanel Margin="10">
        <Label>Unstyled Button</Label>
        <Button>Button 1</Button>
        <Label>Rounded Button</Label>
        <Button>Button 2</Button>
    </StackPanel>
</Window>

アプリケーションを実行すると、次のようになります。If you run the application, it looks like the following:

スタイルが設定されていない 2 つのボタンがある WPF ウィンドウ

ControlTemplate の作成Create a ControlTemplate

ControlTemplate を宣言する最も一般的な方法は、XAML ファイルの Resources セクションのリソースとして宣言する方法です。The most common way to declare a ControlTemplate is as a resource in the Resources section in a XAML file. テンプレートはリソースなので、すべてのリソースに適用されるものと同じスコープ規則に従います。Because templates are resources, they obey the same scoping rules that apply to all resources. つまり、テンプレートの宣言場所は、テンプレートの適用場所に影響するということです。Put simply, where you declare a template affects where the template can be applied. たとえば、アプリケーション定義 XAML ファイルのルート要素でテンプレートを宣言すると、そのテンプレートはアプリケーションのどこでも使用できるようになります。For example, if you declare the template in the root element of your application definition XAML file, the template can be used anywhere in your application. ウィンドウでテンプレートを定義すると、そのテンプレートはウィンドウ内のコントロールでのみ使用できます。If you define the template in a window, only the controls in that window can use the template.

まず、MainWindow.xaml ファイルに Window.Resources 要素を追加します。To start with, add a Window.Resources element to your MainWindow.xaml file:

<Window x:Class="IntroToStylingAndTemplating.Window2"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:IntroToStylingAndTemplating"
        mc:Ignorable="d"
        Title="Template Intro Sample" SizeToContent="WidthAndHeight" MinWidth="250">
    <Window.Resources>
        
    </Window.Resources>
    <StackPanel Margin="10">
        <Label>Unstyled Button</Label>
        <Button>Button 1</Button>
        <Label>Rounded Button</Label>
        <Button>Button 2</Button>
    </StackPanel>
</Window>

次のプロパティ セットで新しい <ControlTemplate> を作成します。Create a new <ControlTemplate> with the following properties set:

x:Keyx:Key roundbutton
TargetType Button

このコントロール テンプレートは単純です。This control template will be simple:

  • コントロールのルート要素である Grida root element for the control, a Grid
  • ボタンの丸みのある外観を描画するための Ellipsean Ellipse to draw the rounded appearance of the button
  • ユーザー指定のボタンの内容を表示する ContentPresentera ContentPresenter to display the user-specified button content
<ControlTemplate x:Key="roundbutton" TargetType="Button">
    <Grid>
        <Ellipse Fill="{TemplateBinding Background}" Stroke="{TemplateBinding Foreground}" />
        <ContentPresenter HorizontalAlignment="Center" VerticalAlignment="Center" />
    </Grid>
</ControlTemplate>

TemplateBindingTemplateBinding

新しい ControlTemplate を作成した場合も、パブリック プロパティを使用して、コントロールの外観を変更する必要が生じる場合があります。When you create a new ControlTemplate, you still might want to use the public properties to change the control's appearance. TemplateBinding のマークアップ拡張機能は、ControlTemplate 内の要素のプロパティを、コントロールで定義されたパブリック プロパティにバインドする機能です。The TemplateBinding markup extension binds a property of an element that is in the ControlTemplate to a public property that is defined by the control. TemplateBinding を使用すると、コントロールのプロパティをテンプレートのパラメーターとして機能させることができます。When you use a TemplateBinding, you enable properties on the control to act as parameters to the template. つまり、コントロールのプロパティを設定すると、その値は TemplateBinding が機能している要素に渡されます。That is, when a property on a control is set, that value is passed on to the element that has the TemplateBinding on it.

EllipseEllipse

<Ellipse> 要素の Fill プロパティおよび Stroke プロパティが、コントロールの Foreground プロパティと Background プロパティにバインドされていることに注意してください。Notice that the Fill and Stroke properties of the <Ellipse> element are bound to the control's Foreground and Background properties.

ContentPresenterContentPresenter

<ContentPresenter> 要素もテンプレートに追加されます。A <ContentPresenter> element is also added to the template. このテンプレートはボタン用に設計されているため、ボタンは ContentControl から継承されることを考慮します。Because this template is designed for a button, take into consideration that the button inherits from ContentControl. このボタンに、要素のコンテンツが表示されます。The button presents the content of the element. ボタン内には、プレーンテキストや別のコントロールなど、任意のものを設定できます。You can set anything inside of the button, such as plain text or even another control. 次のボタンは、いずれも有効です。Both of the following are valid buttons:

<Button>My Text</Button>

<!-- and -->

<Button>
    <CheckBox>Checkbox in a button</CheckBox>
</Button>

前のどちらの例においても、テキストとチェック ボックスは Button.Content プロパティとして設定されています。In both of the previous examples, the text and the checkbox are set as the Button.Content property. コンテンツとして設定されている内容は、テンプレートで実行される <ContentPresenter> によって表示できます。Whatever is set as the content can be presented through a <ContentPresenter>, which is what the template does.

ControlTemplateContentControl 型 (Button など) に適用されている場合は、要素ツリー内で ContentPresenter が検索されます。If the ControlTemplate is applied to a ContentControl type, such as a Button, a ContentPresenter is searched for in the element tree. ContentPresenter が見つかった場合、テンプレートはコントロールの Content プロパティを ContentPresenter に自動的にバインドします。If the ContentPresenter is found, the template automatically binds the control's Content property to the ContentPresenter.

テンプレートを使用するUse the template

この記事の冒頭で宣言したボタンを見つけます。Find the buttons that were declared at the start of this article.

<StackPanel Margin="10">
    <Label>Unstyled Button</Label>
    <Button>Button 1</Button>
    <Label>Rounded Button</Label>
    <Button>Button 2</Button>
</StackPanel>

2 番目のボタンの Template プロパティを次のように roundbutton リソースに設定します。Set the second button's Template property to the roundbutton resource:

<StackPanel Margin="10">
    <Label>Unstyled Button</Label>
    <Button>Button 1</Button>
    <Label>Rounded Button</Label>
    <Button Template="{StaticResource roundbutton}">Button 2</Button>
</StackPanel>

プロジェクトを実行して結果を確認すると、ボタンの背景が丸められていることがわかります。If you run the project and look at the result, you'll see that the button has a rounded background.

テンプレートの楕円のボタンが 1 つ表示されている WPF ウィンドウ

ボタンが円ではなく、歪曲されていることに気付いたかもしれません。You may have noticed that the button isn't a circle but is skewed. <Ellipse> 要素の動作方法により、これらは常に空いているスペースを埋めるように拡張されます。Because of the way the <Ellipse> element works, it always expands to fill the available space. ボタンの width プロパティと height プロパティを同じ値に変更し、円を一定にします。Make the circle uniform by changing the button's width and height properties to the same value:

<StackPanel Margin="10">
    <Label>Unstyled Button</Label>
    <Button>Button 1</Button>
    <Label>Rounded Button</Label>
    <Button Template="{StaticResource roundbutton}" Width="65" Height="65">Button 2</Button>
</StackPanel>

テンプレートの円形のボタンが 1 つ表示されている WPF ウィンドウ

トリガーの追加Add a Trigger

テンプレートが適用されているボタンの見た目が異なる場合でも、他のボタンと同じように動作します。Even though a button with a template applied looks different, it behaves the same as any other button. このボタンを押すと、Click イベントが発生します。If you press the button, the Click event fires. ただし、ボタンの上にマウスを移動しても、ボタンの見た目は変わりません。However, you may have noticed that when you move your mouse over the button, the button's visuals don't change. これらの視覚的な相互作用は、すべてテンプレートによって定義されています。These visual interactions are all defined by the template.

WPF で提供されている動的イベントおよびプロパティ システムを使用して、特定のプロパティの値を監視し、必要に応じてテンプレートのスタイルを再作成することができます。With the dynamic event and property systems that WPF provides, you can watch a specific property for a value and then restyle the template when appropriate. この例では、ボタンの IsMouseOver プロパティを見ていきます。In this example, you'll watch the button's IsMouseOver property. マウスがコントロールの上にあるときに、新しい色で <Ellipse> のスタイルを設定します。When the mouse is over the control, style the <Ellipse> with a new color. この種類のトリガーは、PropertyTrigger として知られています。This type of trigger is known as a PropertyTrigger.

これを機能させるには、参照できる <Ellipse> に名前を追加する必要があります。For this to work, you'll need to add a name to the <Ellipse> that you can reference. backgroundElement という名前を指定します。Give it the name of backgroundElement.

<Ellipse x:Name="backgroundElement" Fill="{TemplateBinding Background}" Stroke="{TemplateBinding Foreground}" />

次に、ControlTemplate.Triggers コレクションに新しい Trigger を追加します。Next, add a new Trigger to the ControlTemplate.Triggers collection. トリガーは、true 値の IsMouseOver イベントを監視します。The trigger will watch the IsMouseOver event for the value true.

<ControlTemplate x:Key="roundbutton" TargetType="Button">
    <Grid>
        <Ellipse x:Name="backgroundElement" Fill="{TemplateBinding Background}" Stroke="{TemplateBinding Foreground}" />
        <ContentPresenter HorizontalAlignment="Center" VerticalAlignment="Center" />
    </Grid>
    <ControlTemplate.Triggers>
        <Trigger Property="IsMouseOver" Value="true">

        </Trigger>
    </ControlTemplate.Triggers>
</ControlTemplate>

次に、 <Ellipse>Fill プロパティを新しい色に変更する <Trigger><Setter> を追加します。Next, add a <Setter> to the <Trigger> that changes the Fill property of the <Ellipse> to a new color.

<Trigger Property="IsMouseOver" Value="true">
    <Setter Property="Fill" TargetName="backgroundElement" Value="AliceBlue"/>
</Trigger>

プロジェクトを実行します。Run the project. ボタンの上にマウスを移動すると、 <Ellipse> の色が変化する点に注意してください。Notice that when you move the mouse over the button, the color of the <Ellipse> changes.

WPF ボタンの上にマウスを移動したことで塗りつぶしの色が変化

VisualState を使用するUse a VisualState

表示状態は、コントロールによって定義され、トリガーされます。Visual states are defined and triggered by a control. たとえば、マウスをコントロールの上に移動すると、CommonStates.MouseOver 状態がトリガーされます。For example, when the mouse is moved on top of the control, the CommonStates.MouseOver state is triggered. コントロールの現在の状態に基づいて、プロパティの変更にアニメーションを付けることができます。You can animate property changes based on the current state of the control. 前のセクションでは、 <PropertyTrigger> を使用して、IsMouseOver プロパティが true である場合にボタンの前景が AliceBlue に変更されるようにしました。In the previous section, a <PropertyTrigger> was used to change the foreground of the button to AliceBlue when the IsMouseOver property was true. 代わりに、この色が変化するアニメーションを付けて、滑らかな遷移を実現する表示状態を作成します。Instead, create a visual state that animates the change of this color, providing a smooth transition. VisualStates の詳細については、「WPF のスタイルとテンプレート」を参照してください。For more information about VisualStates, see Styles and templates in WPF.

<PropertyTrigger> をアニメーションが付いた表示状態に変換するには、まず、テンプレートから <ControlTemplate.Triggers> 要素を削除します。To convert the <PropertyTrigger> to an animated visual state, First, remove the <ControlTemplate.Triggers> element from your template.

<ControlTemplate x:Key="roundbutton" TargetType="Button">
    <Grid>
        <Ellipse x:Name="backgroundElement" Fill="{TemplateBinding Background}" Stroke="{TemplateBinding Foreground}" />
        <ContentPresenter HorizontalAlignment="Center" VerticalAlignment="Center" />
    </Grid>
</ControlTemplate>

次に、コントロール テンプレートの <Grid> ルートで、CommonStates<VisualStateGroup> を指定して <VisualStateManager.VisualStateGroups> 要素を追加します。Next, in the <Grid> root of the control template, add the <VisualStateManager.VisualStateGroups> element with a <VisualStateGroup> for CommonStates. NormalMouseOver の 2 つの状態を定義します。Define two states, Normal and MouseOver.

<ControlTemplate x:Key="roundbutton" TargetType="Button">
    <Grid>
        <VisualStateManager.VisualStateGroups>
            <VisualStateGroup Name="CommonStates">
                <VisualState Name="Normal">
                </VisualState>
                <VisualState Name="MouseOver">
                </VisualState>
            </VisualStateGroup>
        </VisualStateManager.VisualStateGroups>
        <Ellipse x:Name="backgroundElement" Fill="{TemplateBinding Background}" Stroke="{TemplateBinding Foreground}" />
        <ContentPresenter HorizontalAlignment="Center" VerticalAlignment="Center" />
    </Grid>
</ControlTemplate>

<VisualState> で定義されているアニメーションは、その状態がトリガーされたときに適用されます。Any animations defined in a <VisualState> are applied when that state is triggered. 各状態のアニメーションを作成します。Create animations for each state. アニメーションは、 <Storyboard> 要素に格納されます。Animations are put inside of a <Storyboard> element. ストーリーボードの詳細については、「ストーリーボードの概要」を参照してください。For more information about storyboards, see Storyboards Overview.

  • 標準Normal

    この状態では、楕円の塗りつぶしにアニメーションが付けられ、コントロールの Background の色に復元されます。This state animates the ellipse fill, restoring it to the control's Background color.

    <Storyboard>
        <ColorAnimation Storyboard.TargetName="backgroundElement" 
            Storyboard.TargetProperty="(Shape.Fill).(SolidColorBrush.Color)"
            To="{TemplateBinding Background}"
            Duration="0:0:0.3"/>
    </Storyboard>
    
  • MouseOverMouseOver

    この状態では、楕円の Background の色から新しい色である Yellow に切り替わるようアニメーションが付けられます。This state animates the ellipse Background color to a new color: Yellow.

    <Storyboard>
        <ColorAnimation Storyboard.TargetName="backgroundElement" 
            Storyboard.TargetProperty="(Shape.Fill).(SolidColorBrush.Color)" 
            To="Yellow" 
            Duration="0:0:0.3"/>
    </Storyboard>
    

<ControlTemplate> は次のようになるはずです。The <ControlTemplate> should now look like the following.

<ControlTemplate x:Key="roundbutton" TargetType="Button">
    <Grid>
        <VisualStateManager.VisualStateGroups>
            <VisualStateGroup Name="CommonStates">
                <VisualState Name="Normal">
                    <Storyboard>
                        <ColorAnimation Storyboard.TargetName="backgroundElement" 
                            Storyboard.TargetProperty="(Shape.Fill).(SolidColorBrush.Color)"
                            To="{TemplateBinding Background}"
                            Duration="0:0:0.3"/>
                    </Storyboard>
                </VisualState>
                <VisualState Name="MouseOver">
                    <Storyboard>
                        <ColorAnimation Storyboard.TargetName="backgroundElement" 
                            Storyboard.TargetProperty="(Shape.Fill).(SolidColorBrush.Color)" 
                            To="Yellow" 
                            Duration="0:0:0.3"/>
                    </Storyboard>
                </VisualState>
            </VisualStateGroup>
        </VisualStateManager.VisualStateGroups>
        <Ellipse Name="backgroundElement" Fill="{TemplateBinding Background}" Stroke="{TemplateBinding Foreground}" />
        <ContentPresenter x:Name="contentPresenter" HorizontalAlignment="Center" VerticalAlignment="Center" />
    </Grid>
</ControlTemplate>

プロジェクトを実行します。Run the project. ボタンの上にマウスを移動すると、 <Ellipse> の色がアニメーションになる点に注意してください。Notice that when you move the mouse over the button, the color of the <Ellipse> animates.

WPF ボタンの上にマウスを移動したことで塗りつぶしの色が変化

次の手順Next steps