Cara membuat templat untuk kontrol (WPF.NET)

Dengan Windows Presentation Foundation (WPF), Anda dapat menyesuaikan struktur dan perilaku visual kontrol yang ada dengan templat anda sendiri yang dapat digunakan kembali. Templat dapat diterapkan secara global ke aplikasi, jendela, dan halaman Anda, atau langsung ke kontrol. Sebagian besar skenario yang mengharuskan Anda membuat kontrol baru dapat dicakup dengan membuat templat baru untuk kontrol yang sudah ada.

Penting

Dokumentasi Panduan Desktop untuk .NET 7 dan .NET 6 sedang dibangun.

Dalam artikel ini, Anda akan menjelajahi pembuatan baru ControlTemplate untuk Button kontrol.

Kapan membuat ControlTemplate

Kontrol memiliki banyak properti, seperti Background, , Foregrounddan FontFamily. Properti ini mengontrol berbagai aspek tampilan kontrol, tetapi perubahan yang dapat Anda buat dengan mengatur properti ini terbatas. Misalnya, Anda dapat mengatur properti menjadi Foreground biru dan FontStyle miring pada CheckBox. Ketika Anda ingin menyesuaikan tampilan kontrol di luar pengaturan yang dapat dilakukan properti lain pada kontrol, Anda membuat ControlTemplate.

Di sebagian besar antarmuka pengguna, tombol memiliki tampilan umum yang sama: persegi panjang dengan beberapa teks. Jika Anda ingin membuat tombol bulat, Anda dapat membuat kontrol baru yang mewarisi dari tombol atau membuat ulang fungsionalitas tombol. Selain itu, kontrol pengguna baru akan memberikan visual melingkar.

Anda dapat menghindari pembuatan kontrol baru dengan menyesuaikan tata letak visual kontrol yang ada. Dengan tombol bulat, Anda membuat dengan tata letak visual yang ControlTemplate diinginkan.

Di sisi lain, jika Anda memerlukan kontrol dengan fungsionalitas baru, properti yang berbeda, dan pengaturan baru, Anda akan membuat baru UserControl.

Prasyarat

Buat aplikasi WPF baru dan di MainWindow.xaml (atau jendela lain pilihan Anda) atur properti berikut pada <elemen Window>:

Properti Nilai
Title Template Intro Sample
SizeToContent WidthAndHeight
MinWidth 250

Atur konten <elemen Window> ke XAML berikut:

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

Pada akhirnya, file MainWindow.xaml akan terlihat mirip dengan yang berikut ini:

<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>

Jika Anda menjalankan aplikasi, sepertinya berikut ini:

WPF window with two unstyled buttons

Membuat ControlTemplate

Cara paling umum untuk mendeklarasikan ControlTemplate adalah sebagai sumber daya di bagian Resources dalam file XAML. Karena templat adalah sumber daya, templat mematuhi aturan cakupan yang sama yang berlaku untuk semua sumber daya. Sederhananya, di mana Anda mendeklarasikan templat memengaruhi tempat templat dapat diterapkan. Misalnya, jika Anda mendeklarasikan templat dalam elemen akar file XAML definisi aplikasi Anda, templat dapat digunakan di mana saja dalam aplikasi Anda. Jika Anda menentukan templat di jendela, hanya kontrol di jendela tersebut yang dapat menggunakan templat.

Untuk memulai, tambahkan Window.Resources elemen ke file MainWindow.xaml Anda:

<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>

Buat ControlTemplate> baru <dengan kumpulan properti berikut:

Properti Nilai
x:Kunci roundbutton
TargetType Button

Templat kontrol ini akan sederhana:

  • elemen akar untuk kontrol, a Grid
  • untuk Ellipse menggambar tampilan bulat tombol
  • ContentPresenter untuk menampilkan konten tombol yang ditentukan pengguna
<ControlTemplate x:Key="roundbutton" TargetType="Button">
    <Grid>
        <Ellipse Fill="{TemplateBinding Background}" Stroke="{TemplateBinding Foreground}" />
        <ContentPresenter HorizontalAlignment="Center" VerticalAlignment="Center" />
    </Grid>
</ControlTemplate>

Pengikatan Templat

Saat membuat baru ControlTemplate, Anda mungkin masih ingin menggunakan properti publik untuk mengubah tampilan kontrol. Ekstensi markup TemplateBinding mengikat properti elemen yang ada di ControlTemplate properti publik yang ditentukan oleh kontrol. Saat Anda menggunakan TemplateBinding, Anda mengaktifkan properti pada kontrol untuk bertindak sebagai parameter ke templat. Artinya, ketika properti pada kontrol diatur, nilai tersebut diteruskan ke elemen yang memiliki TemplateBinding di atasnya.

Ellipse

Perhatikan bahwa Fill properti dan Stroke elemen< Elips> terikat ke properti dan Background kontrolForeground.

ContentPresenter

Elemen <ContentPresenter> juga ditambahkan ke templat. Karena templat ini dirancang untuk tombol, pertimbangkan bahwa tombol mewarisi dari ContentControl. Tombol menyajikan konten elemen . Anda dapat mengatur apa pun di dalam tombol, seperti teks biasa atau bahkan kontrol lain. Kedua tombol berikut ini adalah tombol yang valid:

<Button>My Text</Button>

<!-- and -->

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

Dalam kedua contoh sebelumnya, teks dan kotak centang diatur sebagai properti Button.Content . Apa pun yang diatur sebagai konten dapat disajikan melalui <ContentPresenter>, yang merupakan apa yang dilakukan templat.

ControlTemplate Jika diterapkan ke ContentControl jenis, seperti Button, dicari ContentPresenter di pohon elemen. ContentPresenter Jika ditemukan, templat secara otomatis mengikat properti kontrol Content ke ContentPresenter.

Menggunakan templat

Temukan tombol yang dideklarasikan di awal artikel ini.

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

Atur properti tombol Template kedua ke roundbutton sumber daya:

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

Jika Anda menjalankan proyek dan melihat hasilnya, Anda akan melihat bahwa tombol memiliki latar belakang bulat.

WPF window with one template oval button

Anda mungkin telah memperhatikan bahwa tombol tersebut bukan lingkaran tetapi condong. Karena cara <kerja elemen Elips, elemen Elips> selalu berkembang untuk mengisi ruang yang tersedia. Buat lingkaran seragam dengan mengubah properti dan height tombol width ke nilai yang sama:

<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>

WPF window with one template circular button

Menambahkan Pemicu

Meskipun tombol dengan templat yang diterapkan terlihat berbeda, tombol tersebut berfungsi sama dengan tombol lainnya. Jika Anda menekan tombol , peristiwa akan Click diaktifkan. Namun, Anda mungkin telah memperhatikan bahwa ketika Anda menggerakkan mouse Anda di atas tombol, visual tombol tidak berubah. Interaksi visual ini semuanya ditentukan oleh templat.

Dengan peristiwa dinamis dan sistem properti yang disediakan WPF, Anda dapat menonton properti tertentu untuk nilai dan kemudian memulihkan templat jika sesuai. Dalam contoh ini, Anda akan menonton properti tombol IsMouseOver . Ketika mouse berada di atas kontrol, gaya <Elips> dengan warna baru. Jenis pemicu ini dikenal sebagai PropertyTrigger.

Agar ini berfungsi, Anda harus menambahkan nama ke <Elips> yang dapat Anda referensikan. Berikan nama backgroundElement.

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

Selanjutnya, tambahkan baru Trigger ke koleksi ControlTemplate.Triggers . Pemicu akan menonton IsMouseOver peristiwa untuk nilai 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>

Selanjutnya, tambahkan Setter ><ke <Pemicu> yang mengubah properti Isian < Elips> ke warna baru.

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

Jalankan proyek. Perhatikan bahwa ketika Anda menggerakkan mouse di atas tombol, warna <Elips> berubah.

mouse moves over WPF button to change the fill color

Menggunakan VisualState

Status visual ditentukan dan dipicu oleh kontrol. Misalnya, ketika mouse dipindahkan di atas kontrol, CommonStates.MouseOver status dipicu. Anda dapat menganimasikan perubahan properti berdasarkan status kontrol saat ini. Di bagian sebelumnya, PropertyTrigger> digunakan untuk mengubah latar belakang tombol menjadi AliceBlue ketika IsMouseOver properti adalah true.< Sebagai gantinya, buat status visual yang menganimasikan perubahan warna ini, memberikan transisi yang lancar. Untuk informasi selengkapnya tentang VisualStates, lihat Gaya dan templat di WPF.

Untuk mengonversi PropertyTrigger> ke status visual animasi, Pertama, hapus <elemen ControlTemplate.Triggers> dari templat Anda.<

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

Selanjutnya, di akar Kisi> templat kontrol, tambahkan< elemen VisualStateManager.VisualStateGroups> dengan <VisualStateGroup> untuk CommonStates.< Tentukan dua status, Normal dan 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>

Animasi apa pun yang ditentukan dalam <VisualState> diterapkan saat status tersebut dipicu. Buat animasi untuk setiap status. Animasi dimasukkan ke <dalam elemen Storyboard> . Untuk informasi selengkapnya tentang papan cerita, lihat Gambaran Umum Papan Cerita.

  • Normal

    Status ini menganimasikan isi elips, memulihkannya ke warna kontrol Background .

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

    Status ini menganimasikan warna elips Background ke warna baru: Yellow.

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

<ControlTemplate> sekarang akan terlihat seperti berikut ini.

<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>

Jalankan proyek. Perhatikan bahwa ketika Anda menggerakkan mouse di atas tombol, warna <elips> menganimasikan.

mouse moves over WPF button to change the fill color with a visual state

Langkah berikutnya