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.

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

Kapan membuat ControlTemplate

Kontrol memiliki banyak properti, seperti Background, Foreground, dan FontFamily. Properti ini mengontrol berbagai aspek tampilan kontrol, tetapi perubahan yang dapat Anda buat dengan mengatur properti ini terbatas. Misalnya, Anda dapat mengatur properti Foreground menjadi biru dan FontStyle menjadi miring pada elemen CheckBox. Ketika Anda ingin menyesuaikan tampilan kontrol lebih daripada yang dapat dilakukan oleh pengaturan properti lainnya 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 menyediakan visual melingkar.

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

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

Prasyarat

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

Harta benda Nilai
Title Template Intro Sample
SizeToContent WidthAndHeight
MinWidth 250

Atur konten elemen Jendela 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 XAML berikut:

<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 gambar berikut:

Jendela WPF dengan dua tombol tanpa gaya

Membuat ControlTemplate

Cara paling umum untuk mendeklarasikan ControlTemplate adalah sebagai sumber daya di bagian Resources dalam file XAML. Karena templat adalah sumber daya, templat mengikuti aturan cakupan yang sama dengan semua sumber daya. Tempat Anda mendeklarasikan templat memengaruhi tempat Anda dapat menerapkannya. Misalnya, jika Anda mendeklarasikan templat dalam elemen akar file XAML definisi aplikasi Anda, Anda dapat menggunakan templat 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> dan atur properti berikut:

Harta benda Nilai
x:Kunci roundbutton
TargetType Button

Templat kontrol ini sederhana:

  • sebuah elemen akar untuk kontrol, Grid
  • Ellipse untuk menggambar tampilan tombol bulat
  • 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 dari elemen yang ada di dalam ControlTemplate ke properti publik yang didefinisikan oleh kontrol tersebut. Saat Anda menggunakan TemplateBinding, Anda mengaktifkan properti pada kontrol untuk berfungsi sebagai parameter bagi templat. Saat Anda mengatur properti pada kontrol, nilai diteruskan ke elemen yang memiliki TemplateBinding.

Ellipse

Properti Isi dan Garis Tepi dari <elemen Elips> terikat dengan properti Foreground dan Background pada kontrol.

ContentPresenter

Templat ini juga menyertakan <elemen ContentPresenter> . Karena templat ini dirancang untuk tombol, ingatlah bahwa tombol mewarisi dari ContentControl. Tombol menampilkan konten elemen. Anda dapat mengatur apa pun di dalam tombol, seperti teks biasa atau bahkan kontrol lain. Kedua contoh berikut 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 ditetapkan sebagai konten dapat disajikan melalui <ContentPresenter>, seperti yang dilakukan templat.

Jika Anda menerapkan ControlTemplate ke tipe ContentControl, seperti Button, templat mencari ContentPresenter di pohon elemen. Jika menemukan ContentPresenter, templat secara otomatis mengikat properti kontrol Content ke ContentPresenter.

Menggunakan templat

Temukan tombol yang Anda deklarasikan 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 Template tombol kedua ke sumber daya roundbutton:

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

Jendela WPF dengan satu tombol oval ber-template

Anda mungkin melihat bahwa tombol tersebut bukan lingkaran tetapi condong. Karena cara kerja elemen Ellipse, elemen ini selalu meluas untuk mengisi ruang yang tersedia. Buat lingkaran seragam dengan mengubah properti width dan height tombol 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>

Jendela WPF dengan satu templat tombol melingkar

Menambahkan pemicu

Meskipun tombol dengan templat yang diterapkan terlihat berbeda, tombol tersebut berfungsi sama dengan tombol lainnya. Jika Anda menekan tombol , peristiwa Click akan diaktifkan. Namun, Anda mungkin melihat bahwa ketika Anda menggerakkan mouse di atas tombol, visual tombol tidak berubah. Templat mendefinisikan interaksi visual ini.

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

Agar fitur ini berfungsi, Anda perlu menambahkan nama ke <Elips> yang dapat Anda referensikan. Beri nama backgroundElement.

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

Selanjutnya, tambahkan baru ke koleksi ControlTemplate.Triggers. Pemicu memantau kejadian IsMouseOver 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 dari <Elips> dengan warna baru.

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

Jalankan proyek. Saat Anda memindahkan mouse ke atas tombol, warna <Elips> berubah.

mouse bergerak di atas tombol WPF untuk mengubah warna isi

Menggunakan VisualState

Status visual ditentukan dan dipicu oleh kontrol. Misalnya, saat Anda memindahkan mouse di atas kontrol, kontrol akan memicu status CommonStates.MouseOver. Anda dapat menganimasikan perubahan properti berdasarkan status kontrol saat ini. Di bagian sebelumnya, Anda menggunakan <PropertyTrigger> 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, 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 templat kontrol Grid <>, 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>

Terapkan animasi apa pun yang <Anda tentukan dalam VisualState> saat status tersebut dipicu. Buat animasi untuk setiap status. Letakkan animasi di dalam <elemen Storyboard> . Untuk informasi selengkapnya tentang papan cerita, lihat Gambaran Umum Storyboards.

  • Biasa

    Keadaan ini menganimasikan warna isi elips, mengembalikannya ke warna Background dari kendali.

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

    Status ini menganimasikan warna Background elips 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 kode berikut.

<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. Saat Anda menggerakkan mouse ke atas tombol, warna <Elips> beranimasi.

mouse bergerak di atas tombol WPF untuk mengubah warna isian dengan keadaan visual

Langkah selanjutnya