Bagikan melalui


Templat kontrol

Telusuri sampel. Telusuri sampel

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:

Cuplikan layar dua objek CardView yang di-template.

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:

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:

Cuplikan layar objek CardView yang di-template.

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

Cuplikan layar objek CardViewUI yang di-template.

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:

Templat kontrol untuk ContentPage.

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:

Cuplikan layar objek halaman templat.

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:

Cuplikan layar objek halaman templat yang 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:

Cuplikan layar tiga objek CardView templat yang mengikat ke viewmodel.

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.