Templat kontrol
Templat kontrol .NET Multi-platform App UI (.NET MAUI) memungkinkan Anda menentukan struktur visual kontrol kustom turunan ContentView , dan ContentPage halaman turunan. Templat kontrol memisahkan antarmuka pengguna (UI) untuk kontrol kustom, atau halaman, dari logika yang mengimplementasikan kontrol atau halaman. Konten tambahan juga dapat disisipkan ke dalam kontrol kustom templat, atau halaman templat, di lokasi yang telah ditentukan sebelumnya.
Misalnya, templat kontrol dapat dibuat yang mendefinisikan ulang UI yang disediakan oleh kontrol kustom. Templat kontrol kemudian dapat digunakan oleh instans kontrol kustom yang diperlukan. Atau, templat kontrol dapat dibuat yang menentukan UI umum yang akan digunakan oleh beberapa halaman dalam aplikasi. Templat kontrol kemudian dapat digunakan oleh beberapa halaman, dengan setiap halaman masih menampilkan konten uniknya.
Membuat ControlTemplate
Contoh berikut menunjukkan kode untuk CardView
kontrol kustom:
public class CardView : ContentView
{
public static readonly BindableProperty CardTitleProperty =
BindableProperty.Create(nameof(CardTitle), typeof(string), typeof(CardView), string.Empty);
public static readonly BindableProperty CardDescriptionProperty =
BindableProperty.Create(nameof(CardDescription), typeof(string), typeof(CardView), string.Empty);
public string CardTitle
{
get => (string)GetValue(CardTitleProperty);
set => SetValue(CardTitleProperty, value);
}
public string CardDescription
{
get => (string)GetValue(CardDescriptionProperty);
set => SetValue(CardDescriptionProperty, value);
}
...
}
Kelas CardView
, yang berasal dari ContentView kelas , mewakili kontrol kustom yang menampilkan data dalam tata letak seperti kartu. Kelas berisi properti, yang didukung oleh properti yang dapat diikat, untuk data yang ditampilkannya. Namun, CardView
kelas tidak menentukan UI apa pun. Sebagai gantinya, UI akan didefinisikan dengan templat kontrol. Untuk informasi selengkapnya tentang membuat ContentView kontrol kustom turunan, lihat ContentView.
Templat kontrol dibuat dengan jenis .ControlTemplate Saat Anda membuat ControlTemplate, Anda menggabungkan View objek untuk membangun UI untuk kontrol kustom, atau halaman. Harus ControlTemplate memiliki hanya satu View sebagai elemen akarnya. Namun, elemen root biasanya berisi objek lain View . Kombinasi objek membentuk struktur visual kontrol.
ControlTemplate Meskipun dapat didefinisikan sebaris, pendekatan umum untuk mendeklarasikan ControlTemplate adalah sebagai sumber daya dalam kamus sumber daya. Karena templat kontrol adalah sumber daya, templat tersebut mematuhi aturan cakupan yang sama yang berlaku untuk semua sumber daya. Misalnya, jika Anda mendeklarasikan templat kontrol di kamus sumber daya tingkat aplikasi, templat dapat digunakan di mana saja di aplikasi Anda. Jika Anda menentukan templat di halaman, hanya halaman tersebut yang dapat menggunakan templat kontrol. Untuk informasi selengkapnya tentang sumber daya, lihat Kamus sumber daya.
Contoh XAML berikut menunjukkan ControlTemplate untuk CardView
objek:
<ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
...>
<ContentPage.Resources>
<ControlTemplate x:Key="CardViewControlTemplate">
<Frame BindingContext="{Binding Source={RelativeSource TemplatedParent}}"
BackgroundColor="{Binding CardColor}"
BorderColor="{Binding BorderColor}"
...>
<!-- UI objects that define the CardView visual structure -->
</Frame>
</ControlTemplate>
</ContentPage.Resources>
...
</ContentPage>
ControlTemplate Ketika dinyatakan sebagai sumber daya, itu harus memiliki kunci yang ditentukan dengan x:Key
atribut sehingga dapat diidentifikasi dalam kamus sumber daya. Dalam contoh ini, elemen akar adalah CardViewControlTemplate
Frame objek. Objek Frame menggunakan ekstensi markup untuk mengaturnya BindingContext ke instans RelativeSource
objek runtime tempat templat akan diterapkan, yang dikenal sebagai induk yang di-template. Objek Frame menggunakan kombinasi kontrol untuk menentukan struktur CardView
visual objek. Ekspresi pengikatan objek ini diselesaikan terhadap CardView
properti, karena mewarisi BindingContext dari elemen akar Frame . Untuk informasi selengkapnya tentang RelativeSource
ekstensi markup, lihat Pengikatan relatif.
Mengonsumsi ControlTemplate
ControlTemplate Dapat diterapkan ke ContentView kontrol kustom turunan dengan mengatur propertinya ControlTemplate ke objek templat kontrol. Demikian pula, ControlTemplate dapat diterapkan ke ContentPage halaman turunan dengan mengatur propertinya ControlTemplate ke objek templat kontrol. Pada runtime, saat ControlTemplate diterapkan, semua kontrol yang ditentukan dalam ControlTemplate ditambahkan ke pohon visual kontrol kustom yang di-templat, atau halaman templat.
Contoh berikut menunjukkan yang CardViewControlTemplate
ditetapkan ke ControlTemplate properti dari dua CardView
objek:
<ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:controls="clr-namespace:ControlTemplateDemos.Controls"
...>
<StackLayout Margin="30">
<controls:CardView BorderColor="DarkGray"
CardTitle="John Doe"
CardDescription="Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nulla elit dolor, convallis non interdum."
IconBackgroundColor="SlateGray"
IconImageSource="user.png"
ControlTemplate="{StaticResource CardViewControlTemplate}" />
<controls:CardView BorderColor="DarkGray"
CardTitle="Jane Doe"
CardDescription="Phasellus eu convallis mi. In tempus augue eu dignissim fermentum. Morbi ut lacus vitae eros lacinia."
IconBackgroundColor="SlateGray"
IconImageSource="user.png"
ControlTemplate="{StaticResource CardViewControlTemplate}" />
</StackLayout>
</ContentPage>
Dalam contoh ini, kontrol dalam CardViewControlTemplate
menjadi bagian dari pohon visual untuk setiap CardView
objek. Karena objek akar Frame untuk templat kontrol mengaturnya BindingContext ke induk yang di-template, Frame dan anak-anaknya menyelesaikan ekspresi pengikatannya terhadap properti setiap CardView
objek.
Cuplikan layar berikut menunjukkan CardViewControlTemplate
yang diterapkan ke CardView
objek:
Penting
Titik waktu yang ControlTemplate diterapkan ke instans kontrol dapat dideteksi dengan mengambil alih OnApplyTemplate metode dalam kontrol kustom templat, atau halaman templat. Untuk informasi selengkapnya, lihat Mendapatkan elemen bernama dari templat.
Meneruskan parameter dengan TemplateBinding
Ekstensi TemplateBinding
markup mengikat properti elemen yang berada di ControlTemplate properti publik yang ditentukan oleh kontrol kustom templat atau halaman templat. Saat Anda menggunakan TemplateBinding
, Anda mengaktifkan properti pada kontrol untuk bertindak sebagai parameter ke templat. Oleh karena itu, ketika properti pada kontrol kustom templat atau halaman templat diatur, nilai tersebut diteruskan ke elemen yang memilikinya TemplateBinding
.
Penting
TemplateBinding
Ekspresi markup memungkinkan pengikatan RelativeSource
dari templat kontrol sebelumnya dihapus, dan mengganti Binding
ekspresi.
TemplateBinding
Ekstensi markup menentukan properti berikut:
- Path, dari jenis
string
, jalur ke properti . - Mode, dari jenis BindingMode, arah di mana perubahan menyebar antara sumber dan target.
- Converter, dari jenis IValueConverter, pengonversi nilai pengikatan.
- ConverterParameter, dari jenis
object
, parameter ke pengonversi nilai pengikatan. - StringFormat, dari jenis
string
, format string untuk pengikatan.
ContentProperty
Untuk TemplateBinding
ekstensi markup adalah Path. Oleh karena itu, bagian "Path=" dari ekstensi markup dapat dihilangkan jika jalur adalah item pertama dalam TemplateBinding
ekspresi. Untuk informasi selengkapnya tentang menggunakan properti ini dalam ekspresi pengikatan, lihat Pengikatan data.
Peringatan
Ekstensi TemplateBinding
markup hanya boleh digunakan dalam ControlTemplate. Namun, mencoba menggunakan TemplateBinding
ekspresi di luar ControlTemplate tidak akan mengakibatkan kesalahan build atau pengecualian dilemparkan.
Contoh XAML berikut menunjukkan ControlTemplate untuk CardView
objek, yang menggunakan TemplateBinding
ekstensi markup:
<ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
...>
<ContentPage.Resources>
<ControlTemplate x:Key="CardViewControlTemplate">
<Frame BackgroundColor="{TemplateBinding CardColor}"
BorderColor="{TemplateBinding BorderColor}"
...>
<!-- UI objects that define the CardView visual structure -->
</Frame>
</ControlTemplate>
</ContentPage.Resources>
...
</ContentPage>
Dalam contoh ini, TemplateBinding
ekstensi markup menyelesaikan ekspresi pengikatan terhadap properti setiap CardView
objek. Cuplikan layar berikut menunjukkan CardViewControlTemplate
yang diterapkan ke CardView
objek:
Penting
TemplateBinding
Menggunakan ekstensi markup setara dengan mengatur BindingContext elemen akar dalam templat ke induk templatnya dengan RelativeSource
ekstensi markup, lalu menyelesaikan pengikatan objek anak dengan Binding
ekstensi markup. Bahkan, TemplateBinding
ekstensi markup membuat yang Binding
Source
adalah RelativeBindingSource.TemplatedParent
.
Menerapkan ControlTemplate dengan gaya
Templat kontrol juga dapat diterapkan dengan gaya. Ini dicapai dengan membuat gaya implisit ControlTemplateatau eksplisit yang menggunakan .
Contoh XAML berikut menunjukkan gaya implisit CardViewControlTemplate
yang menggunakan :
<ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:controls="clr-namespace:ControlTemplateDemos.Controls"
...>
<ContentPage.Resources>
<ControlTemplate x:Key="CardViewControlTemplate">
...
</ControlTemplate>
<Style TargetType="controls:CardView">
<Setter Property="ControlTemplate"
Value="{StaticResource CardViewControlTemplate}" />
</Style>
</ContentPage.Resources>
<StackLayout Margin="30">
<controls:CardView BorderColor="DarkGray"
CardTitle="John Doe"
CardDescription="Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nulla elit dolor, convallis non interdum."
IconBackgroundColor="SlateGray"
IconImageSource="user.png" />
...
</StackLayout>
</ContentPage>
Dalam contoh ini, implisit Style secara otomatis diterapkan ke setiap CardView
objek, dan mengatur ControlTemplate properti masing-masing CardView
ke CardViewControlTemplate
.
Untuk informasi selengkapnya tentang gaya, lihat Gaya.
Menenangkan ulang UI kontrol
Ketika dibuat dan ditetapkan ke ControlTemplate properti kontrol kustom turunanContentView, atau ContentPage halaman turunan, struktur visual yang ControlTemplate ditentukan untuk kontrol atau halaman kustom diganti dengan struktur visual yang ditentukan dalam ControlTemplate.
Misalnya, CardViewUI
kontrol kustom menentukan antarmuka penggunanya menggunakan XAML berikut:
<ContentView xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="ControlTemplateDemos.Controls.CardViewUI"
x:Name="this">
<Frame BindingContext="{x:Reference this}"
BackgroundColor="{Binding CardColor}"
BorderColor="{Binding BorderColor}"
...>
<!-- UI objects that define the CardView visual structure -->
</Frame>
</ContentView>
Namun, kontrol yang terdiri dari UI ini dapat diganti dengan menentukan struktur visual baru dalam ControlTemplate, dan menetapkannya ke ControlTemplate properti CardViewUI
objek:
<ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
...>
<ContentPage.Resources>
<ControlTemplate x:Key="CardViewCompressed">
<Grid RowDefinitions="100"
ColumnDefinitions="100, *">
<Image Source="{TemplateBinding IconImageSource}"
BackgroundColor="{TemplateBinding IconBackgroundColor}"
...>
<!-- Other UI objects that define the CardView visual structure -->
</Grid>
</ControlTemplate>
</ContentPage.Resources>
<StackLayout Margin="30">
<controls:CardViewUI BorderColor="DarkGray"
CardTitle="John Doe"
CardDescription="Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nulla elit dolor, convallis non interdum."
IconBackgroundColor="SlateGray"
IconImageSource="user.png"
ControlTemplate="{StaticResource CardViewCompressed}" />
...
</StackLayout>
</ContentPage>
Dalam contoh ini, struktur CardViewUI
visual objek didefinisikan ulang dalam ControlTemplate yang menyediakan struktur visual yang lebih ringkas yang cocok untuk daftar ringkas:
Mengganti konten menjadi ContentPresenter
ContentPresenter Dapat ditempatkan dalam templat kontrol untuk menandai tempat konten ditampilkan oleh kontrol kustom templat atau halaman templat akan muncul. Kontrol kustom atau halaman yang menggunakan templat kontrol kemudian akan menentukan konten yang akan ditampilkan oleh ContentPresenter. Diagram berikut mengilustrasikan ControlTemplate untuk halaman yang berisi sejumlah kontrol, termasuk yang ContentPresenter ditandai dengan persegi panjang biru:
XAML berikut menunjukkan templat kontrol bernama TealTemplate
yang berisi ContentPresenter dalam struktur visualnya:
<ControlTemplate x:Key="TealTemplate">
<Grid RowDefinitions="0.1*, 0.8*, 0.1*">
<BoxView Color="Teal" />
<Label Margin="20,0,0,0"
Text="{TemplateBinding HeaderText}"
... />
<ContentPresenter Grid.Row="1" />
<BoxView Grid.Row="2"
Color="Teal" />
<Label x:Name="changeThemeLabel"
Grid.Row="2"
Margin="20,0,0,0"
Text="Change Theme"
...>
<Label.GestureRecognizers>
<TapGestureRecognizer Tapped="OnChangeThemeLabelTapped" />
</Label.GestureRecognizers>
</Label>
<controls:HyperlinkLabel Grid.Row="2"
Margin="0,0,20,0"
Text="Help"
Url="https://learn.microsoft.com/dotnet/maui/"
... />
</Grid>
</ControlTemplate>
Contoh berikut menunjukkan TealTemplate
ditetapkan ke ControlTemplate properti halaman turunan ContentPage :
<controls:HeaderFooterPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:controls="clr-namespace:ControlTemplateDemos.Controls"
ControlTemplate="{StaticResource TealTemplate}"
HeaderText="MyApp"
...>
<StackLayout Margin="10">
<Entry Placeholder="Enter username" />
<Entry Placeholder="Enter password"
IsPassword="True" />
<Button Text="Login" />
</StackLayout>
</controls:HeaderFooterPage>
Pada runtime, ketika TealTemplate
diterapkan ke halaman, konten halaman diganti ke dalam yang ContentPresenter ditentukan dalam templat kontrol:
Mendapatkan elemen bernama dari templat
Elemen bernama dalam templat kontrol dapat diambil dari kontrol kustom templat atau halaman templat. Ini dapat dicapai dengan GetTemplateChild metode , yang mengembalikan elemen bernama di pohon visual yang dibuat ControlTemplate , jika ditemukan. Jika tidak, ia kembali null
.
Setelah templat kontrol dibuat, metode templat OnApplyTemplate dipanggil. Oleh karena itu GetTemplateChild , metode harus dipanggil dari OnApplyTemplate penimpaan di halaman kontrol templat atau templat.
Penting
Metode GetTemplateChild ini hanya boleh dipanggil setelah OnApplyTemplate metode dipanggil.
XAML berikut menunjukkan templat kontrol bernama TealTemplate
yang dapat diterapkan ke ContentPage halaman turunan:
<ControlTemplate x:Key="TealTemplate">
<Grid>
...
<Label x:Name="changeThemeLabel"
Text="Change Theme"
...>
<Label.GestureRecognizers>
<TapGestureRecognizer Tapped="OnChangeThemeLabelTapped" />
</Label.GestureRecognizers>
</Label>
...
</Grid>
</ControlTemplate>
Dalam contoh ini, Label elemen diberi nama, dan dapat diambil dalam kode untuk halaman templat. Ini dicapai dengan memanggil GetTemplateChild metode dari OnApplyTemplate penimpaan untuk halaman templat:
public partial class AccessTemplateElementPage : HeaderFooterPage
{
Label themeLabel;
public AccessTemplateElementPage()
{
InitializeComponent();
}
protected override void OnApplyTemplate()
{
base.OnApplyTemplate();
themeLabel = (Label)GetTemplateChild("changeThemeLabel");
themeLabel.Text = OriginalTemplate ? "Aqua Theme" : "Teal Theme";
}
}
Dalam contoh ini, Label objek bernama changeThemeLabel
diambil setelah ControlTemplate telah diinstansiasi. changeThemeLabel
kemudian dapat diakses dan dimanipulasi oleh AccessTemplateElementPage
kelas . Cuplikan layar berikut menunjukkan bahwa teks yang Label ditampilkan oleh telah diubah:
Ikat ke viewmodel
ControlTemplate dapat mengikat data ke viewmodel, bahkan ketika ControlTemplate pengikatan ke induk templat (instans objek runtime tempat templat diterapkan).
Contoh XAML berikut menunjukkan halaman yang menggunakan viewmodel bernama PeopleViewModel
:
<ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:local="clr-namespace:ControlTemplateDemos"
xmlns:controls="clr-namespace:ControlTemplateDemos.Controls"
...>
<ContentPage.BindingContext>
<local:PeopleViewModel />
</ContentPage.BindingContext>
<ContentPage.Resources>
<DataTemplate x:Key="PersonTemplate">
<controls:CardView BorderColor="DarkGray"
CardTitle="{Binding Name}"
CardDescription="{Binding Description}"
ControlTemplate="{StaticResource CardViewControlTemplate}" />
</DataTemplate>
</ContentPage.Resources>
<StackLayout Margin="10"
BindableLayout.ItemsSource="{Binding People}"
BindableLayout.ItemTemplate="{StaticResource PersonTemplate}" />
</ContentPage>
Dalam contoh ini, BindingContext halaman diatur ke PeopleViewModel
instans. Viewmodel ini mengekspos People
koleksi dan bernama ICommand DeletePersonCommand
. StackLayout Pada halaman menggunakan tata letak yang dapat diikat ke pengikatan data ke People
koleksi, dan ItemTemplate
tata letak yang dapat diikat diatur ke PersonTemplate
sumber daya. Ini DataTemplate menentukan bahwa setiap item dalam People
koleksi akan ditampilkan menggunakan CardView
objek. Struktur CardView
visual objek didefinisikan menggunakan bernama ControlTemplate CardViewControlTemplate
:
<ControlTemplate x:Key="CardViewControlTemplate">
<Frame BindingContext="{Binding Source={RelativeSource TemplatedParent}}"
BackgroundColor="{Binding CardColor}"
BorderColor="{Binding BorderColor}"
...>
<!-- UI objects that define the CardView visual structure -->
</Frame>
</ControlTemplate>
Dalam contoh ini, elemen akar adalah ControlTemplate Frame objek. Objek Frame menggunakan RelativeSource
ekstensi markup untuk mengaturnya BindingContext ke induk templat. Ekspresi Frame pengikatan objek dan anak-anaknya mengatasi CardView
properti, karena mewarisi BindingContext dari elemen akar Frame . Cuplikan layar berikut menunjukkan halaman yang People
menampilkan koleksi:
Saat objek dalam ikatan ControlTemplate ke properti pada induk templatnya, Button dalam templat kontrol mengikat ke induk templatnya, dan ke DeletePersonCommand
di viewmodel. Ini karena Button.Command
properti mendefinisikan ulang sumber pengikatannya menjadi konteks pengikatan leluhur yang jenis konteks pengikatannya adalah PeopleViewModel
, yang merupakan StackLayout. Bagian Path
dari ekspresi pengikatan kemudian dapat menyelesaikan DeletePersonCommand
properti . Namun, Button.CommandParameter
properti tidak mengubah sumber pengikatannya, sebagai gantinya mewarisinya dari induknya di ControlTemplate. Oleh karena itu, CommandParameter
properti mengikat properti CardTitle
dari CardView
.
Efek keseluruhan dari Button pengikatan adalah bahwa ketika Button diketuk, DeletePersonCommand
di PeopleViewModel
kelas dijalankan, dengan nilai CardName
properti diteruskan ke DeletePersonCommand
. Ini menghasilkan yang ditentukan CardView
dihapus dari tata letak yang dapat diikat.
Untuk informasi selengkapnya tentang pengikatan relatif, lihat Pengikatan relatif.