Xamarin.Forms szablony kontrolek
Xamarin.Forms szablony kontrolek umożliwiają definiowanie struktury wizualnej pochodnych ContentView
kontrolek niestandardowych i ContentPage
stron pochodnych. Szablony kontrolek oddzielają interfejs użytkownika dla kontrolki niestandardowej lub strony od logiki implementujące kontrolkę lub stronę. Dodatkową zawartość można również wstawić do szablonowej kontrolki niestandardowej lub strony szablonu w wstępnie zdefiniowanej lokalizacji.
Na przykład można utworzyć szablon kontrolki, który ponownie definiuje interfejs użytkownika udostępniany przez kontrolkę niestandardową. Następnie szablon kontrolki może być używany przez wymagane wystąpienie kontrolki niestandardowej. Alternatywnie można utworzyć szablon kontrolki, który definiuje dowolny wspólny interfejs użytkownika, który będzie używany przez wiele stron w aplikacji. Szablon kontrolki może być następnie używany przez wiele stron, a każda strona nadal wyświetla swoją unikatową zawartość.
Tworzenie elementu ControlTemplate
W poniższym przykładzie pokazano kod kontrolki niestandardowej CardView
:
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);
}
// ...
}
Klasa CardView
, która pochodzi z ContentView
klasy, reprezentuje kontrolkę niestandardową, która wyświetla dane w układzie przypominającym kartę. Klasa zawiera właściwości, które są wspierane przez powiązane właściwości dla wyświetlanych danych. CardView
Jednak klasa nie definiuje żadnego interfejsu użytkownika. Zamiast tego interfejs użytkownika zostanie zdefiniowany przy użyciu szablonu kontrolki. Aby uzyskać więcej informacji na temat tworzenia ContentView
pochodnych kontrolek niestandardowych, zobacz Xamarin.Forms ContentView.
Szablon kontrolki jest tworzony przy użyciu ControlTemplate
typu . Podczas tworzenia obiektu ControlTemplate
połączysz View
obiekty w celu skompilowania interfejsu użytkownika dla kontrolki niestandardowej lub strony. Element ControlTemplate
musi mieć tylko jeden View
element główny. Jednak element główny zwykle zawiera inne View
obiekty. Kombinacja obiektów tworzy strukturę wizualizacji kontrolki.
ControlTemplate
Chociaż element można zdefiniować w tekście, typowe podejście do deklarowania elementu ControlTemplate
jest jako zasób w słowniku zasobów. Ponieważ szablony kontrolek są zasobami, przestrzegają tych samych reguł określania zakresu, które mają zastosowanie do wszystkich zasobów. Jeśli na przykład zadeklarujesz szablon kontrolki w elemecie głównym pliku XAML definicji aplikacji, szablon może być używany w dowolnym miejscu w aplikacji. Jeśli zdefiniujesz szablon na stronie, tylko ta strona może używać szablonu kontrolki. Aby uzyskać więcej informacji na temat zasobów, zobacz Xamarin.Forms Słowniki zasobów.
Poniższy przykład XAML przedstawia ControlTemplate
obiekt dla CardView
obiektów:
<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>
Gdy element ControlTemplate
jest zadeklarowany jako zasób, musi mieć klucz określony za pomocą atrybutu x:Key
, aby można było go zidentyfikować w słowniku zasobów. W tym przykładzie element główny obiektu CardViewControlTemplate
jest obiektem Frame
. Obiekt Frame
używa RelativeSource
rozszerzenia znaczników, aby ustawić jego BindingContext
wystąpienie obiektu środowiska uruchomieniowego, do którego zostanie zastosowany szablon, który jest znany jako szablon nadrzędny. Obiekt Frame
używa kombinacji Grid
obiektów , , Frame
Image
, Label
i BoxView
do definiowania struktury wizualnej CardView
obiektu. Wyrażenia powiązania tych obiektów są rozpoznawane względem CardView
właściwości ze względu na dziedziczenie BindingContext
elementu głównego Frame
. Aby uzyskać więcej informacji na temat RelativeSource
rozszerzenia znaczników, zobacz Xamarin.Forms Względne powiązania.
Korzystanie z kontrolkiTemplate
Obiekt ControlTemplate
można zastosować do pochodnej kontrolki niestandardowej ContentView
, ustawiając jej ControlTemplate
właściwość na obiekt szablonu kontrolki. Podobnie obiekt można zastosować do strony pochodnejContentPage
, ControlTemplate
ustawiając jej ControlTemplate
właściwość na obiekt szablonu kontrolki. W czasie wykonywania, gdy ControlTemplate
element jest stosowany, wszystkie kontrolki zdefiniowane w obiekcie ControlTemplate
są dodawane do drzewa wizualnego kontrolki niestandardowej szablonu lub strony szablonu.
W poniższym przykładzie pokazano przypisanie CardViewControlTemplate
ControlTemplate
do właściwości każdego CardView
obiektu:
<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>
W tym przykładzie CardViewControlTemplate
kontrolki w stanie się częścią drzewa wizualnego dla każdego CardView
obiektu. Ponieważ obiekt główny Frame
szablonu kontrolki ustawia go BindingContext
na szablon obiektu nadrzędnego, Frame
a jego elementy podrzędne rozpoznają ich wyrażenia powiązania względem właściwości każdego CardView
obiektu.
Na poniższych zrzutach ekranu przedstawiono CardViewControlTemplate
zastosowane do trzech CardView
obiektów:
Ważne
Punkt w czasie, ControlTemplate
który jest stosowany do wystąpienia kontrolki, można wykryć przez zastąpienie OnApplyTemplate
metody w szablonowej kontrolce niestandardowej lub stronie szablonu. Aby uzyskać więcej informacji, zobacz Pobieranie nazwanego elementu z szablonu.
Przekazywanie parametrów za pomocą funkcji TemplateBinding
TemplateBinding
Rozszerzenie znaczników wiąże właściwość elementu, który znajduje się w ControlTemplate
właściwości publicznej zdefiniowanej przez szablonową kontrolkę niestandardową lub stronę szablonu. Gdy używasz TemplateBinding
elementu , włączasz właściwości kontrolki tak, aby działały jako parametry szablonu. W związku z tym po ustawieniu właściwości na niestandardowej kontrolce szablonu lub stronie szablonu ta wartość jest przekazywana do elementu, który ma TemplateBinding
na nim wartość.
Ważne
Wyrażenie TemplateBinding
znaczników umożliwia RelativeSource
usunięcie powiązania z poprzedniego szablonu kontrolki i zastąpienie wyrażeń Binding
.
Rozszerzenie TemplateBinding
znaczników definiuje następujące właściwości:
Path
, typustring
, ścieżka do właściwości .Mode
, typuBindingMode
, kierunek, w którym zmiany są propagowane między źródłem a obiektem docelowym.Converter
, typuIValueConverter
, konwerter wartości powiązania.ConverterParameter
, typuobject
, parametr do konwertera wartości powiązania.StringFormat
, typustring
, format ciągu dla powiązania.
TemplateBinding
Dla ContentProperty
rozszerzenia znaczników to Path
. W związku z tym część "Path=" rozszerzenia znaczników można pominąć, jeśli ścieżka jest pierwszym elementem w wyrażeniu TemplateBinding
. Aby uzyskać więcej informacji na temat używania tych właściwości w wyrażeniu powiązania, zobacz Xamarin.Forms Powiązanie danych.
Ostrzeżenie
Rozszerzenie TemplateBinding
znaczników powinno być używane tylko w obrębie .ControlTemplate
Jednak próba użycia TemplateBinding
wyrażenia poza obiektem ControlTemplate
nie spowoduje wystąpienia błędu kompilacji lub zgłoszenia wyjątku.
Poniższy przykład XAML przedstawia ControlTemplate
obiekt dla CardView
obiektów korzystających z TemplateBinding
rozszerzenia znaczników:
<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>
W tym przykładzie TemplateBinding
rozszerzenie znaczników rozpoznaje wyrażenia powiązania względem właściwości każdego CardView
obiektu. Na poniższych zrzutach ekranu przedstawiono CardViewControlTemplate
zastosowane do trzech CardView
obiektów:
Ważne
TemplateBinding
Użycie rozszerzenia znaczników jest równoważne ustawieniu BindingContext
elementu głównego w szablonie na jego szablon nadrzędny RelativeSource
z rozszerzeniem znaczników, a następnie rozpoznawanie powiązań obiektów podrzędnych z Binding
rozszerzeniem znaczników. W rzeczywistości TemplateBinding
rozszerzenie znaczników tworzy obiekt, którego Binding
Source
element ma wartość RelativeBindingSource.TemplatedParent
.
Stosowanie kontrolkiTemplate z stylem
Szablony kontrolek można również stosować za pomocą stylów. Jest to osiągane przez utworzenie niejawnego lub jawnego stylu, który używa elementu ControlTemplate
.
Poniższy przykład XAML przedstawia niejawny styl, który korzysta z elementu CardViewControlTemplate
:
<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>
W tym przykładzie niejawna Style
funkcja jest automatycznie stosowana do każdego CardView
obiektu i ustawia ControlTemplate
właściwość każdego CardView
obiektu na CardViewControlTemplate
wartość .
Aby uzyskać więcej informacji na temat stylów, zobacz Xamarin.Forms Style.
Ponowne definiowanie interfejsu użytkownika kontrolki
Gdy element ControlTemplate
jest tworzony i przypisywany do ControlTemplate
właściwości pochodnej ContentView
kontrolki niestandardowej lub ContentPage
strony pochodnej, struktura wizualizacji zdefiniowana dla kontrolki niestandardowej lub strony jest zastępowana strukturą wizualizacji zdefiniowaną w obiekcie ControlTemplate
.
Na przykład kontrolka niestandardowa CardViewUI
definiuje interfejs użytkownika przy użyciu następującego kodu XAML:
<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>
Jednak kontrolki składające się z tego interfejsu użytkownika można zastąpić przez zdefiniowanie nowej struktury wizualizacji w ControlTemplate
obiekcie i przypisanie jej do ControlTemplate
właściwości CardViewUI
obiektu:
<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>
W tym przykładzie struktura wizualizacji CardViewUI
obiektu jest ponownie definiowana w obiekcie ControlTemplate
, który zapewnia bardziej kompaktową strukturę wizualną odpowiednią dla listy skondensowanej:
Podstawianie zawartości do elementu ContentPresenter
Element ContentPresenter
można umieścić w szablonie kontrolki, aby oznaczyć, gdzie będzie wyświetlana zawartość za pomocą szablonowej kontrolki niestandardowej lub strony szablonu. Niestandardowa kontrolka lub strona korzystająca z szablonu kontrolki zdefiniuje zawartość, która ma być wyświetlana ContentPresenter
przez element . Na poniższym diagramie przedstawiono ControlTemplate
stronę zawierającą wiele kontrolek, w tym ContentPresenter
oznaczone niebieskim prostokątem:
Poniższy kod XAML przedstawia szablon kontrolki o nazwie TealTemplate
zawierający element ContentPresenter
w jego strukturze wizualnej:
<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>
W poniższym przykładzie pokazano TealTemplate
przypisaną ControlTemplate
do właściwości strony pochodnej 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>
W czasie wykonywania, gdy TealTemplate
jest stosowany do strony, zawartość strony jest zastępowana w ContentPresenter
zdefiniowanym w szablonie kontrolki:
Pobieranie nazwanego elementu z szablonu
Nazwane elementy w szablonie kontrolki można pobrać z szablonu niestandardowej kontrolki lub strony szablonu. Można to osiągnąć za GetTemplateChild
pomocą metody , która zwraca nazwany ControlTemplate
element w utworzonej wizualizacji drzewa, jeśli zostanie znaleziona. W przeciwnym razie zwraca wartość null
.
Po utworzeniu wystąpienia szablonu kontrolki wywoływana OnApplyTemplate
jest metoda szablonu. W GetTemplateChild
związku z tym metoda powinna być wywoływana z OnApplyTemplate
przesłonięcia w kontrolce szablonu lub na stronie szablonu.
Ważne
Metoda GetTemplateChild
powinna być wywoływana tylko po wywołaniu OnApplyTemplate
metody.
Poniższy kod XAML przedstawia szablon kontrolki o nazwie TealTemplate
, który można zastosować do ContentPage
stron pochodnych:
<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>
W tym przykładzie Label
element ma nazwę i można go pobrać w kodzie strony szablonu. Jest to osiągane przez wywołanie GetTemplateChild
metody z OnApplyTemplate
przesłonięcia dla strony szablonu:
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";
}
}
W tym przykładzie Label
obiekt o nazwie changeThemeLabel
jest pobierany po utworzeniu ControlTemplate
wystąpienia obiektu . changeThemeLabel
następnie można uzyskać dostęp do klasy i manipulować nią AccessTemplateElementPage
. Na poniższych zrzutach ekranu pokazano, że tekst wyświetlany przez Label
element został zmieniony:
Wiązanie z modelem widoku
Obiekt ControlTemplate
może powiązać dane z modelem viewmodel, nawet jeśli ControlTemplate
powiązanie z szablonem elementu nadrzędnego (wystąpienie obiektu środowiska uruchomieniowego, do którego zastosowano szablon).
Poniższy przykład XAML przedstawia stronę, która korzysta z modelu viewmodel o nazwie 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>
W tym przykładzie BindingContext
strona jest ustawiona PeopleViewModel
na wystąpienie. Ten model widoku uwidacznia People
kolekcję i ICommand
nazwę DeletePersonCommand
. Na StackLayout
stronie jest używany układ możliwy do People
powiązania z danymi powiązanymi z kolekcją, a ItemTemplate
układ wiązania jest ustawiony na PersonTemplate
zasób. Określa, DataTemplate
że każdy element w People
kolekcji będzie wyświetlany przy użyciu CardView
obiektu. Struktura CardView
wizualna obiektu jest definiowana ControlTemplate
przy użyciu nazwy CardViewControlTemplate
:
<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>
W tym przykładzie element główny obiektu ControlTemplate
jest obiektem Frame
. Obiekt Frame
używa RelativeSource
rozszerzenia znaczników, aby ustawić go BindingContext
na szablon elementu nadrzędnego. Wyrażenia powiązania obiektu i jego elementów podrzędnych Frame
są rozpoznawane względem CardView
właściwości z powodu dziedziczenia BindingContext
z elementu głównego Frame
. Na poniższych zrzutach ekranu przedstawiono stronę z wyświetloną kolekcją People
składającą się z trzech elementów:
Obiekty w powiązaniu ControlTemplate
z właściwościami w szablonie elementu nadrzędnego, Button
natomiast szablon kontrolki jest powiązany zarówno z elementem nadrzędnym szablonu, jak i z obiektem DeletePersonCommand
w modelu viewmodel. Jest to spowodowane tym, że Button.Command
właściwość ponownie definiuje jego źródło powiązania jako kontekst powiązania obiektu nadrzędnego, którego typ kontekstu powiązania to PeopleViewModel
, czyli StackLayout
. Część Path
wyrażeń powiązania może następnie rozpoznać DeletePersonCommand
właściwość . Button.CommandParameter
Jednak właściwość nie zmienia źródła powiązania, zamiast tego dziedziczy ją z elementu nadrzędnego w obiekcie ControlTemplate
. W związku z tym CommandParameter
właściwość wiąże się z właściwością CardTitle
CardView
.
Ogólny efekt Button
powiązań polega na tym, DeletePersonCommand
że po Button
naciśnięciu elementu w PeopleViewModel
klasie wykonywana jest wartość CardName
właściwości przekazywanej DeletePersonCommand
do klasy . Spowoduje to usunięcie określonego CardView
układu możliwego do powiązania:
Aby uzyskać więcej informacji na temat powiązań względnych, zobacz Xamarin.Forms Powiązania względne.