Bagikan melalui


Xamarin.Forms templat kontrol

Xamarin.Forms templat kontrol 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 antarmuka pengguna 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 Xamarin.Forms 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 elemen akar file XAML definisi aplikasi Anda, templat dapat digunakan di mana saja dalam aplikasi Anda. Jika Anda menentukan templat di halaman, hanya halaman tersebut yang dapat menggunakan templat kontrol. Untuk informasi selengkapnya tentang sumber daya, lihat Xamarin.Forms Kamus Sumber Daya.

Contoh XAML berikut menunjukkan ControlTemplate untuk CardView objek:

<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
             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}"
                 CornerRadius="5"
                 HasShadow="True"
                 Padding="8"
                 HorizontalOptions="Center"
                 VerticalOptions="Center">
              <Grid>
                  <Grid.RowDefinitions>
                      <RowDefinition Height="75" />
                      <RowDefinition Height="4" />
                      <RowDefinition Height="Auto" />
                  </Grid.RowDefinitions>
                  <Grid.ColumnDefinitions>
                      <ColumnDefinition Width="75" />
                      <ColumnDefinition Width="200" />
                  </Grid.ColumnDefinitions>
                  <Frame IsClippedToBounds="True"
                         BorderColor="{Binding BorderColor}"
                         BackgroundColor="{Binding IconBackgroundColor}"
                         CornerRadius="38"
                         HeightRequest="60"
                         WidthRequest="60"
                         HorizontalOptions="Center"
                         VerticalOptions="Center">
                      <Image Source="{Binding IconImageSource}"
                             Margin="-20"
                             WidthRequest="100"
                             HeightRequest="100"
                             Aspect="AspectFill" />
                  </Frame>
                  <Label Grid.Column="1"
                         Text="{Binding CardTitle}"
                         FontAttributes="Bold"
                         FontSize="Large"
                         VerticalTextAlignment="Center"
                         HorizontalTextAlignment="Start" />
                  <BoxView Grid.Row="1"
                           Grid.ColumnSpan="2"
                           BackgroundColor="{Binding BorderColor}"
                           HeightRequest="2"
                           HorizontalOptions="Fill" />
                  <Label Grid.Row="2"
                         Grid.ColumnSpan="2"
                         Text="{Binding CardDescription}"
                         VerticalTextAlignment="Start"
                         VerticalOptions="Fill"
                         HorizontalOptions="Fill" />
              </Grid>
          </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 CardViewControlTemplateFrame 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 Gridobjek , , FrameImage, Label, dan BoxView 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 Xamarin.Forms 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 setiap CardView objek:

<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
             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}" />
        <controls:CardView BorderColor="DarkGray"
                           CardTitle="Xamarin Monkey"
                           CardDescription="Aliquam sagittis, odio lacinia fermentum dictum, mi erat scelerisque erat, quis aliquet arcu."
                           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 yang CardViewControlTemplate diterapkan ke tiga CardView objek:

Cuplikan layar objek CardView yang di-template, di iOS dan Android

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 Xamarin.Forms 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://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             ...>
    <ContentPage.Resources>
        <ControlTemplate x:Key="CardViewControlTemplate">
            <Frame BackgroundColor="{TemplateBinding CardColor}"
                   BorderColor="{TemplateBinding BorderColor}"
                   CornerRadius="5"
                   HasShadow="True"
                   Padding="8"
                   HorizontalOptions="Center"
                   VerticalOptions="Center">
                <Grid>
                    <Grid.RowDefinitions>
                        <RowDefinition Height="75" />
                        <RowDefinition Height="4" />
                        <RowDefinition Height="Auto" />
                    </Grid.RowDefinitions>
                    <Grid.ColumnDefinitions>
                        <ColumnDefinition Width="75" />
                        <ColumnDefinition Width="200" />
                    </Grid.ColumnDefinitions>
                    <Frame IsClippedToBounds="True"
                           BorderColor="{TemplateBinding BorderColor}"
                           BackgroundColor="{TemplateBinding IconBackgroundColor}"
                           CornerRadius="38"
                           HeightRequest="60"
                           WidthRequest="60"
                           HorizontalOptions="Center"
                           VerticalOptions="Center">
                        <Image Source="{TemplateBinding IconImageSource}"
                               Margin="-20"
                               WidthRequest="100"
                               HeightRequest="100"
                               Aspect="AspectFill" />
                    </Frame>
                    <Label Grid.Column="1"
                           Text="{TemplateBinding CardTitle}"
                           FontAttributes="Bold"
                           FontSize="Large"
                           VerticalTextAlignment="Center"
                           HorizontalTextAlignment="Start" />
                    <BoxView Grid.Row="1"
                             Grid.ColumnSpan="2"
                             BackgroundColor="{TemplateBinding BorderColor}"
                             HeightRequest="2"
                             HorizontalOptions="Fill" />
                    <Label Grid.Row="2"
                           Grid.ColumnSpan="2"
                           Text="{TemplateBinding CardDescription}"
                           VerticalTextAlignment="Start"
                           VerticalOptions="Fill"
                           HorizontalOptions="Fill" />
                </Grid>
            </Frame>
        </ControlTemplate>
    </ContentPage.Resources>
    ...
</ContentPage>

Dalam contoh ini, TemplateBinding ekstensi markup menyelesaikan ekspresi pengikatan terhadap properti setiap CardView objek. Cuplikan layar berikut menunjukkan yang CardViewControlTemplate diterapkan ke tiga 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 BindingSource adalah RelativeBindingSource.TemplatedParent.

Menerapkan ControlTemplate dengan gaya

Templat kontrol juga dapat diterapkan dengan gaya. Ini dicapai dengan membuat gaya implisitControlTemplateatau eksplisit yang menggunakan .

Contoh XAML berikut menunjukkan gaya implisitCardViewControlTemplateyang menggunakan :

<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
             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" />
        <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"/>
        <controls:CardView BorderColor="DarkGray"
                           CardTitle="Xamarin Monkey"
                           CardDescription="Aliquam sagittis, odio lacinia fermentum dictum, mi erat scelerisque erat, quis aliquet arcu."
                           IconBackgroundColor="SlateGray"
                           IconImageSource="user.png" />
    </StackLayout>
</ContentPage>

Dalam contoh ini, implisitStyle secara otomatis diterapkan ke setiap CardView objek, dan mengatur ControlTemplate properti masing-masing CardView ke CardViewControlTemplate.

Untuk informasi selengkapnya tentang gaya, lihat Xamarin.Forms 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://xamarin.com/schemas/2014/forms"
             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}"
           CornerRadius="5"
           HasShadow="True"
           Padding="8"
           HorizontalOptions="Center"
           VerticalOptions="Center">
        <Grid>
            <Grid.RowDefinitions>
                <RowDefinition Height="75" />
                <RowDefinition Height="4" />
                <RowDefinition Height="Auto" />
            </Grid.RowDefinitions>
            <Grid.ColumnDefinitions>
                <ColumnDefinition Width="75" />
                <ColumnDefinition Width="200" />
            </Grid.ColumnDefinitions>
            <Frame IsClippedToBounds="True"
                   BorderColor="{Binding BorderColor, FallbackValue='Black'}"
                   BackgroundColor="{Binding IconBackgroundColor, FallbackValue='Gray'}"
                   CornerRadius="38"
                   HeightRequest="60"
                   WidthRequest="60"
                   HorizontalOptions="Center"
                   VerticalOptions="Center">
                <Image Source="{Binding IconImageSource}"
                       Margin="-20"
                       WidthRequest="100"
                       HeightRequest="100"
                       Aspect="AspectFill" />
            </Frame>
            <Label Grid.Column="1"
                   Text="{Binding CardTitle, FallbackValue='Card title'}"
                   FontAttributes="Bold"
                   FontSize="Large"
                   VerticalTextAlignment="Center"
                   HorizontalTextAlignment="Start" />
            <BoxView Grid.Row="1"
                     Grid.ColumnSpan="2"
                     BackgroundColor="{Binding BorderColor, FallbackValue='Black'}"
                     HeightRequest="2"
                     HorizontalOptions="Fill" />
            <Label Grid.Row="2"
                   Grid.ColumnSpan="2"
                   Text="{Binding CardDescription, FallbackValue='Card description'}"
                   VerticalTextAlignment="Start"
                   VerticalOptions="Fill"
                   HorizontalOptions="Fill" />
        </Grid>
    </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://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             ...>
    <ContentPage.Resources>
        <ControlTemplate x:Key="CardViewCompressed">
            <Grid>
                <Grid.RowDefinitions>
                    <RowDefinition Height="100" />
                </Grid.RowDefinitions>
                <Grid.ColumnDefinitions>
                    <ColumnDefinition Width="100" />
                    <ColumnDefinition Width="*" />
                </Grid.ColumnDefinitions>
                <Image Source="{TemplateBinding IconImageSource}"
                        BackgroundColor="{TemplateBinding IconBackgroundColor}"
                        WidthRequest="100"
                        HeightRequest="100"
                        Aspect="AspectFill"
                        HorizontalOptions="Center"
                        VerticalOptions="Center" />
                <StackLayout Grid.Column="1">
                    <Label Text="{TemplateBinding CardTitle}"
                           FontAttributes="Bold" />
                    <Label Text="{TemplateBinding CardDescription}" />
                </StackLayout>
            </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}" />
        <controls:CardViewUI 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 CardViewCompressed}" />
        <controls:CardViewUI BorderColor="DarkGray"
                             CardTitle="Xamarin Monkey"
                             CardDescription="Aliquam sagittis, odio lacinia fermentum dictum, mi erat scelerisque erat, quis aliquet arcu."
                             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, di iOS dan Android

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>
        <Grid.RowDefinitions>
            <RowDefinition Height="0.1*" />
            <RowDefinition Height="0.8*" />
            <RowDefinition Height="0.1*" />
        </Grid.RowDefinitions>
        <BoxView Color="Teal" />
        <Label Margin="20,0,0,0"
               Text="{TemplateBinding HeaderText}"
               TextColor="White"
               FontSize="Title"
               VerticalOptions="Center" />
        <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"
               TextColor="White"
               HorizontalOptions="Start"
               VerticalOptions="Center">
            <Label.GestureRecognizers>
                <TapGestureRecognizer Tapped="OnChangeThemeLabelTapped" />
            </Label.GestureRecognizers>
        </Label>
        <controls:HyperlinkLabel Grid.Row="2"
                                 Margin="0,0,20,0"
                                 Text="Help"
                                 TextColor="White"
                                 Url="https://learn.microsoft.com/xamarin/xamarin-forms/"
                                 HorizontalOptions="End"
                                 VerticalOptions="Center" />
    </Grid>
</ControlTemplate>

Contoh berikut menunjukkan TealTemplate ditetapkan ke ControlTemplate properti halaman turunan ContentPage :

<controls:HeaderFooterPage xmlns="http://xamarin.com/schemas/2014/forms"
                           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, di iOS dan Android

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"
               Grid.Row="2"
               Margin="20,0,0,0"
               Text="Change Theme"
               TextColor="White"
               HorizontalOptions="Start"
               VerticalOptions="Center">
            <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

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://xamarin.com/schemas/2014/forms"
             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 ICommandDeletePersonCommand. 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 ControlTemplateCardViewControlTemplate:

<ControlTemplate x:Key="CardViewControlTemplate">
    <Frame BindingContext="{Binding Source={RelativeSource TemplatedParent}}"
           BackgroundColor="{Binding CardColor}"
           BorderColor="{Binding BorderColor}"
           CornerRadius="5"
           HasShadow="True"
           Padding="8"
           HorizontalOptions="Center"
           VerticalOptions="Center">
        <Grid>
            <Grid.RowDefinitions>
                <RowDefinition Height="75" />
                <RowDefinition Height="4" />
                <RowDefinition Height="Auto" />
            </Grid.RowDefinitions>
            <Label Text="{Binding CardTitle}"
                   FontAttributes="Bold"
                   FontSize="Large"
                   VerticalTextAlignment="Center"
                   HorizontalTextAlignment="Start" />
            <BoxView Grid.Row="1"
                     BackgroundColor="{Binding BorderColor}"
                     HeightRequest="2"
                     HorizontalOptions="Fill" />
            <Label Grid.Row="2"
                   Text="{Binding CardDescription}"
                   VerticalTextAlignment="Start"
                   VerticalOptions="Fill"
                   HorizontalOptions="Fill" />
            <Button Text="Delete"
                    Command="{Binding Source={RelativeSource AncestorType={x:Type local:PeopleViewModel}}, Path=DeletePersonCommand}"
                    CommandParameter="{Binding CardTitle}"
                    HorizontalOptions="End" />
        </Grid>
    </Frame>
</ControlTemplate>

Dalam contoh ini, elemen akar adalah ControlTemplateFrame 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 menampilkan People koleksi, yang terdiri dari tiga item:

Cuplikan layar tiga objek CardView yang di-template

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:

Cuplikan layar dua objek CardView yang di-template

Untuk informasi selengkapnya tentang pengikatan relatif, lihat Xamarin.Forms Pengikatan Relatif.