Šablony ovládacích prvků
Šablony ovládacích prvků .NET Multi-Platform App UI (.NET MAUI) umožňují definovat vizuální strukturu odvozených vlastních ovládacích ContentView prvků a ContentPage odvozených stránek. Šablony ovládacích prvků oddělují uživatelské rozhraní pro vlastní ovládací prvek nebo stránku od logiky, která implementuje ovládací prvek nebo stránku. Do předdefinovaného umístění lze také vložit další obsah do vlastního ovládacího prvku šablony nebo na stránku šablony.
Můžete například vytvořit šablonu ovládacího prvku, která předefinuje uživatelské rozhraní, které poskytuje vlastní ovládací prvek. Šablonu ovládacího prvku pak může spotřebovat požadovaná instance vlastního ovládacího prvku. Alternativně lze vytvořit šablonu ovládacího prvku, která definuje jakékoli společné uživatelské rozhraní, které bude používat více stránek v aplikaci. Šablonu ovládacího prvku pak může využívat více stránek, přičemž každá stránka stále zobrazuje svůj jedinečný obsah.
Vytvoření ControlTemplate
Následující příklad ukazuje kód vlastního CardView
ovládacího prvku:
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);
}
...
}
Třída CardView
, která je odvozena z ContentView třídy, představuje vlastní ovládací prvek, který zobrazuje data v rozložení podobné kartě. Třída obsahuje vlastnosti, které jsou podporovány vazebnými vlastnostmi, pro data, která zobrazí. CardView
Třída však nedefinuje žádné uživatelské rozhraní. Místo toho se uživatelské rozhraní definuje pomocí šablony ovládacího prvku. Další informace o vytváření ContentView odvozených vlastních ovládacích prvků naleznete v tématu ContentView.
Vytvoří se šablona ovládacího prvku s typem ControlTemplate . Když vytvoříte objekty ControlTemplate, zkombinujete View objekty pro vytvoření uživatelského rozhraní pro vlastní ovládací prvek nebo stránku. A ControlTemplate musí mít pouze jeden View jako jeho kořenový prvek. Kořenový prvek však obvykle obsahuje jiné View objekty. Kombinace objektů tvoří vizuální strukturu ovládacího prvku.
I když lze definovat vložený ControlTemplate přístup, typický přístup k deklarování ControlTemplate je jako prostředek ve slovníku prostředků. Protože šablony ovládacích prvků jsou prostředky, dodržují stejná pravidla oborů, která platí pro všechny prostředky. Pokud například deklarujete šablonu ovládacího prvku ve slovníku prostředků na úrovni aplikace, můžete ji použít kdekoli v aplikaci. Pokud šablonu definujete na stránce, může použít pouze tuto šablonu ovládacího prvku. Další informace o prostředcích najdete v tématu Slovníky prostředků.
Následující příklad XAML ukazuje ControlTemplate objekty CardView
:
<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 Když je deklarován jako prostředek, musí mít klíč zadaný s x:Key
atributem, aby ho bylo možné identifikovat ve slovníku prostředků. V tomto příkladu je kořenovým prvkem objektu CardViewControlTemplate
Frame . Objekt Frame používá RelativeSource
rozšíření značek k nastavení jeho BindingContext na instanci objektu runtime, na kterou se šablona použije, což se označuje jako nadřazený objekt šablony. Objekt Frame používá kombinaci ovládacích prvků k definování vizuální struktury objektu CardView
. Vazbové výrazy těchto objektů se přeloží na CardView
vlastnosti, protože dědí BindingContext z kořenového Frame elementu. Další informace o RelativeSource
rozšíření značek naleznete v tématu Relativní vazby.
Využití controlTemplate
A ControlTemplate lze použít na odvozený ContentView vlastní ovládací prvek nastavením jeho ControlTemplate vlastnosti na objekt šablony ovládacího prvku. ControlTemplate Podobně lze použít na odvozenou ContentPage stránku nastavením jeho ControlTemplate vlastnosti na objekt šablony ovládacího prvku. Za běhu se při ControlTemplate použití všech ovládacích prvků definovaných v šabloně ControlTemplate vlastního ovládacího prvku nebo stránky šablony přidají do vizuálního stromu.
Následující příklad ukazuje CardViewControlTemplate
přiřazení vlastnosti ControlTemplate dvou CardView
objektů:
<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>
V tomto příkladu se ovládací prvky v rámci CardViewControlTemplate
vizuálního stromu stanou součástí každého CardView
objektu. Vzhledem k tomu, že kořenový Frame objekt šablony ovládacího prvku nastaví jeho BindingContext na nadřazenou šablonu, Frame a její podřízené položky přeloží své vazby výrazy proti vlastnostem každého CardView
objektu.
Následující snímek obrazovky ukazuje CardViewControlTemplate
použité objekty CardView
:
Důležité
Bod v čase, který ControlTemplate se použije na instanci ovládacího prvku, lze zjistit přepsáním OnApplyTemplate metody v šabloně vlastního ovládacího prvku nebo stránkou šablony. Další informace naleznete v tématu Získání pojmenovaného elementu ze šablony.
Předání parametrů pomocí TemplateBinding
Rozšíření TemplateBinding
značek vytvoří vazbu vlastnosti elementu, který je ve ControlTemplate veřejné vlastnosti, která je definována šablonou vlastní ovládací prvek nebo stránka šablony. Když použijete TemplateBinding
příkaz , povolíte vlastnosti ovládacího prvku tak, aby fungovaly jako parametry šablony. Proto když je nastavena vlastnost na šabloně vlastní ovládací prvek nebo stránka šablony, tato hodnota je předána do elementu, který má TemplateBinding
na něm.
Důležité
Výraz TemplateBinding
značky RelativeSource
umožňuje odebrat vazbu z předchozí šablony ovládacího prvku a nahradit Binding
výrazy.
Rozšíření TemplateBinding
značek definuje následující vlastnosti:
- Path, typu
string
, cesta k vlastnosti. - Mode, typu BindingMode, směr, ve kterém se změny šíří mezi zdrojem a cílem.
- Converter, typu IValueConverter, převaděč hodnoty vazby.
- ConverterParameter, typu
object
, parametr pro převaděč hodnoty vazby. - StringFormat, typu
string
, formát řetězce pro vazbu.
TemplateBinding
Pro ContentProperty
rozšíření značek je Path. Proto lze část "Path=" rozšíření značek vynechat, pokud je cesta první položkou ve výrazu TemplateBinding
. Další informace o použití těchto vlastností ve výrazu vazby naleznete v tématu Datové vazby.
Upozorňující
Rozšíření TemplateBinding
značek by mělo být použito pouze v rámci .ControlTemplate Pokus o použití výrazu TemplateBinding
mimo objekt ControlTemplate však nebude mít za následek chybu sestavení nebo vyvolání výjimky.
Následující příklad XAML ukazuje ControlTemplate objekty CardView
, které používají TemplateBinding
rozšíření značek:
<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>
V tomto příkladu TemplateBinding
rozšíření značek překládá vazby výrazy proti vlastnostem každého CardView
objektu. Následující snímek obrazovky ukazuje CardViewControlTemplate
použité objekty CardView
:
Důležité
TemplateBinding
Použití rozšíření značek je ekvivalentní nastavení BindingContext kořenového prvku v šabloně na jeho šablonované nadřazené objekty s RelativeSource
rozšířením značek a poté překlad vazeb podřízených objektů s rozšířením Binding
značek. Ve skutečnosti TemplateBinding
rozšíření značek vytvoří Binding
, jehož Source
je RelativeBindingSource.TemplatedParent
.
Použití ControlTemplate se stylem
Šablony ovládacích prvků lze použít také se styly. Toho dosáhnete vytvořením implicitního nebo explicitního stylu, který využívá ControlTemplate.
Následující příklad XAML ukazuje implicitní styl, který využívá CardViewControlTemplate
:
<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>
V tomto příkladu se implicitní Style automaticky použije u každého CardView
objektu a nastaví ControlTemplate vlastnost každého CardView
objektu na CardViewControlTemplate
.
Další informace o stylech naleznete v tématu Styly.
Předefinovat uživatelské rozhraní ovládacího prvku
ControlTemplate Při vytvoření instance a přiřazení k ControlTemplate vlastnosti odvozeného ContentView vlastního ovládacího prvku nebo odvozené ContentPage stránky, vizuální struktura definovaná pro vlastní ovládací prvek nebo stránku se nahradí vizuální strukturou definovanou v sadě ControlTemplate.
Vlastní ovládací prvek například CardViewUI
definuje své uživatelské rozhraní pomocí následujícího kódu XAML:
<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>
Ovládací prvky, které tvoří toto uživatelské rozhraní, lze však nahradit definováním nové vizuální struktury v objektu ControlTemplatea jeho přiřazením k ControlTemplate vlastnosti objektu CardViewUI
:
<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>
V tomto příkladu je vizuální struktura objektu CardViewUI
předdefinována, ControlTemplate která poskytuje kompaktnější vizuální strukturu, která je vhodná pro zhuštěný seznam:
Nahrazení obsahu do ContentPresenteru
Šablonu ContentPresenter ovládacího prvku lze umístit do šablony ovládacího prvku a označit tak, kde se zobrazí obsah, který se má zobrazit pomocí vlastního ovládacího prvku nebo stránky šablony. Vlastní ovládací prvek nebo stránka, která využívá šablonu ovládacího prvku, pak definuje obsah, který se má zobrazit pomocí ContentPresenter. Následující diagram znázorňuje ControlTemplate stránku, která obsahuje řadu ovládacích prvků včetně ContentPresenter označeného modrým obdélníkem:
Následující xaml ukazuje šablonu ovládacího prvku s názvem TealTemplate
, která obsahuje ContentPresenter ve své vizuální struktuře:
<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>
Následující příklad ukazuje TealTemplate
přiřazenou ControlTemplate vlastnost odvozené ContentPage stránky:
<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>
Při použití na stránku za běhu TealTemplate
se obsah stránky nahradí ContentPresenter definovaným v šabloně ovládacího prvku:
Získání pojmenovaného elementu ze šablony
Pojmenované prvky v rámci šablony ovládacího prvku lze načíst ze šablony vlastního ovládacího prvku nebo šablony stránky. Toho lze dosáhnout pomocí GetTemplateChild metody, která vrátí pojmenovaný prvek v instanci ControlTemplate vizuální strom, pokud je nalezen. V opačném případě se vrátí null
.
Po vytvoření instance šablony ovládacího prvku se volá metoda šablony OnApplyTemplate . Metoda GetTemplateChild by proto měla být volána z OnApplyTemplate přepsání v ovládacím prvku šablony nebo šablonované stránce.
Důležité
Metoda GetTemplateChild by měla být volána pouze po OnApplyTemplate zavolání metody.
Následující XAML ukazuje šablonu ovládacího prvku s názvem TealTemplate
, kterou lze použít na ContentPage odvozené stránky:
<ControlTemplate x:Key="TealTemplate">
<Grid>
...
<Label x:Name="changeThemeLabel"
Text="Change Theme"
...>
<Label.GestureRecognizers>
<TapGestureRecognizer Tapped="OnChangeThemeLabelTapped" />
</Label.GestureRecognizers>
</Label>
...
</Grid>
</ControlTemplate>
V tomto příkladu Label je element pojmenovaný a lze jej načíst v kódu pro stránku se šablonou. Toho dosáhnete voláním GetTemplateChild metody z OnApplyTemplate přepsání pro stránku šablony:
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";
}
}
V tomto příkladu se po changeThemeLabel
vytvoření instance objektu Label načteControlTemplate. changeThemeLabel
je pak možné přistupovat ke třídě a manipulovat s nimi AccessTemplateElementPage
. Následující snímek obrazovky ukazuje, že došlo ke změně textu zobrazeného uživatelem Label :
Vytvoření vazby k modelu viewmodel
A ControlTemplate může vytvořit vazbu dat na model viewmodel, i když ControlTemplate vazby k nadřazené šabloně (instance objektu runtime, na kterou je šablona použita).
Následující příklad XAML ukazuje stránku, která využívá model viewmodel s názvem 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>
V tomto příkladu BindingContext je stránka nastavená na PeopleViewModel
instanci. Tento model zobrazení zveřejňuje kolekci People
a pojmenovanou ICommand DeletePersonCommand
. Na StackLayout stránce se používá rozložení s možností vazby k datům v People
kolekci a ItemTemplate
rozložení s možností vázání je nastaveno na PersonTemplate
prostředek. Určuje DataTemplate , že každá položka v People
kolekci bude zobrazena pomocí objektu CardView
. Vizuální struktura objektu CardView
je definována pomocí pojmenované 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>
V tomto příkladu je kořenovým prvkem objektu ControlTemplate Frame . Objekt Frame používá RelativeSource
rozšíření značek k nastavení jeho BindingContext na šablonované nadřazené. Vazbové výrazy objektu Frame a jeho podřízené položky se přeloží proti CardView
vlastnostem, protože dědí BindingContext z kořenového Frame elementu. Následující snímek obrazovky ukazuje stránku zobrazující kolekci People
:
Zatímco objekty v vazbě ControlTemplate na vlastnosti v nadřazené šabloně, Button v rámci šablony ovládacího prvku vytvoří vazbu na jeho šablony nadřazené objekty a DeletePersonCommand
v modelu viewmodel. Důvodem je, že Button.Command
vlastnost předekfinuje svůj zdroj vazby jako kontext vazby nadřazeného objektu, jehož typ vazby je PeopleViewModel
, což je StackLayout. Část Path
vazebních výrazů pak může tuto vlastnost přeložit DeletePersonCommand
. Button.CommandParameter
Vlastnost však nezmění svůj zdroj vazby, ale dědí ho z nadřazeného objektu v objektu ControlTemplate. Proto vlastnost CommandParameter
vytvoří vazbu na CardTitle
vlastnost CardView
.
Celkový účinek Button vazeb spočívá v tom, že při klepnutí, Button DeletePersonCommand
ve PeopleViewModel
třídě se spustí hodnota CardName
vlastnosti, která se předává do objektu DeletePersonCommand
. Výsledkem je odebrání zadaného CardView
rozložení s možností vytvoření vazby.
Další informace o relativních vazbách naleznete v tématu Relativní vazby.