Xamarin.Forms Základní vazby
Xamarin.Forms Datová vazba propojuje dvojici vlastností mezi dvěma objekty, z nichž nejméně jeden je obvykle objekt uživatelského rozhraní. Tyto dva objekty se označují jako cíl a zdroj:
- Cíl je objekt (a vlastnost), u kterého se datová vazba nastavuje.
- Zdroj je objekt (a vlastnost), na který datová vazba odkazuje.
Tento rozdíl může být někdy trochu matoucí: V nejjednodušším případě data proudí ze zdroje do cíle, což znamená, že hodnota cílové vlastnosti je nastavena z hodnoty zdrojové vlastnosti. V některých případech ale můžou data naopak proudit z cíle do zdroje nebo oběma směry. Pro ujasnění pamatujte na to, že cíl je vždy objekt, u kterého se datová vazba nastavuje, i kdyby nepřijímal data, ale poskytoval.
Vazby s kontextem
I když se datové vazby obvykle zadávají zcela v jazyce XAML, je poučné podívat se na ně v kódu. Stránka Basic Code Binding (Základní vazba v kódu) obsahuje soubor XAML s objekty Label
a Slider
:
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="DataBindingDemos.BasicCodeBindingPage"
Title="Basic Code Binding">
<StackLayout Padding="10, 0">
<Label x:Name="label"
Text="TEXT"
FontSize="48"
HorizontalOptions="Center"
VerticalOptions="CenterAndExpand" />
<Slider x:Name="slider"
Maximum="360"
VerticalOptions="CenterAndExpand" />
</StackLayout>
</ContentPage>
Objekt Slider
se nastavuje na hodnotu v rozsahu od 0 do 360. Účelem tohoto programu je otáčet objektem Label
prostřednictvím úprav objektu Slider
.
Bez datových vazeb byste nastavili událost ValueChanged
objektu Slider
na obslužnou rutinu události, která by přistupovala k vlastnosti Value
objektu Slider
a nastavovala tuto hodnotu pro vlastnost Rotation
objektu Label
. Datová vazba tuto úlohu automatizuje. Obslužná rutina události a kód v ní už nejsou potřebné.
Vazbu je možné nastavit u instance libovolné třídy odvozené od třídy BindableObject
. Patří mezi ně třídy Element
, VisualElement
nebo View
a třídy odvozené z třídy View
. Vazba se vždy nastavuje u cílového objektu. Vazba odkazuje na zdrojový objekt. Pokud chcete nastavit datovou vazbu, použijte následující dva členy cílové třídy:
- Vlastnost
BindingContext
určuje zdrojový objekt. - Metoda
SetBinding
určuje vlastnost cíle a vlastnost zdroje.
V tomto příkladu je objekt Label
cílem vazby a objekt Slider
je zdrojem vazby. Změny zdroje Slider
ovlivňují otočení cíle Label
. Data proudí ze zdroje do cíle.
Metoda SetBinding
definovaná ve třídě BindableObject
má argument typu BindingBase
, ze kterého odvozuje třída Binding
, ale existují také další metody SetBinding
definované třídou BindableObjectExtensions
. Soubor kódu na pozadí v ukázce Basic Code Binding používá jednodušší rozšiřující metodu SetBinding
z této třídy.
public partial class BasicCodeBindingPage : ContentPage
{
public BasicCodeBindingPage()
{
InitializeComponent();
label.BindingContext = slider;
label.SetBinding(Label.RotationProperty, "Value");
}
}
Objekt Label
je cílem vazby, takže toto je objekt, u kterého se tato vlastnost nastavuje a pro který se volá metoda. Vlastnost BindingContext
označuje zdroj vazby, kterým je objekt Slider
.
Metoda SetBinding
se volá pro cíl vazby, ale určuje jak vlastnost cíle, tak vlastnost zdroje. Vlastnost cíle je zadaná jako objekt BindableProperty
: Label.RotationProperty
. Vlastnost zdroje je zadaná jako řetězec a určuje vlastnost Value
objektu Slider
.
Metoda SetBinding
odhaluje jedno z nejdůležitějších pravidel datových vazeb:
Vlastnost cíle musí být podpořená vlastností umožňující vazbu.
Toto pravidlo implikuje, že cílový objekt musí být instancí třídy, která je odvozená z třídy BindableObject
. Přehled objektů a vlastností umožňujících vazby najdete v článku o vlastnostech s možností vazby.
Pro vlastnost zdroje, která je zadaná jako řetězec, žádné takové pravidlo neplatí. Interně se k přístupu ke skutečné vlastnosti používá reflexe. V tomto konkrétním případě je ale vlastnost Value
také podpořená vlastností umožňující vazbu.
Kód lze poněkud zjednodušit: Vlastnost RotationProperty
bindable je definována VisualElement
a zděděna Label
a ContentPage
také, takže název třídy není vyžadován ve SetBinding
volání:
label.SetBinding(RotationProperty, "Value");
Zahrnutí názvu třídy je ale dobrým připomenutím cílového objektu.
Při úpravách objektu Slider
se příslušným způsobem otáčí objekt Label
:
Stránka Basic Xaml Binding (Základní vazba v Xaml) je prakticky stejná jako stránka Basic Code Binding (Základní vazba v kódu). Rozdíl je jenom v tom, že celá datová vazba je na ní definovaná v jazyce XAML:
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="DataBindingDemos.BasicXamlBindingPage"
Title="Basic XAML Binding">
<StackLayout Padding="10, 0">
<Label Text="TEXT"
FontSize="80"
HorizontalOptions="Center"
VerticalOptions="CenterAndExpand"
BindingContext="{x:Reference Name=slider}"
Rotation="{Binding Path=Value}" />
<Slider x:Name="slider"
Maximum="360"
VerticalOptions="CenterAndExpand" />
</StackLayout>
</ContentPage>
Stejně jako v kódu se datová vazba nastavuje u cílového objektu, tedy Label
. Jsou zapojená dvě rozšíření značek XAML. Ta se dají okamžitě rozpoznat podle svých oddělovačů, kterými jsou složené závorky:
- Rozšíření značek
x:Reference
je potřebné pro odkazování na zdrojový objekt, kterým je objektSlider
s názvemslider
. - Rozšíření značek
Binding
propojuje vlastnostRotation
objektuLabel
s vlastnostíValue
objektuSlider
.
Další informace o rozšířeních značek XAML najdete v článku Rozšíření značek XAML. Rozšíření značek x:Reference
je podporované třídou ReferenceExtension
. Rozšíření značek Binding
je podporované třídou BindingExtension
. Jak označují předpony oboru názvů XML, x:Reference
je součástí specifikace XAML 2009, zatímco Binding
je součástí Xamarin.Forms. Všimněte si, že ve složených závorkách nejsou žádné uvozovky.
Při nastavování vlastnosti BindingContext
je snadné zapomenout na rozšíření značek x:Reference
. Je běžné, že se tato vlastnost chybně nastaví přímo na název zdroje vazby, například takto:
BindingContext="slider"
To ale není správně. Tento kód nastaví vlastnost BindingContext
na objekt string
obsahující znaky slider.
Všimněte si, že vlastnost zdroje je určená vlastností Path
třídy BindingExtension
, která odpovídá vlastnosti Path
třídy Binding
.
Kód zobrazený na stránce základní vazby XAML může být zjednodušený: Rozšíření značek XAML, jako x:Reference
jsou a Binding
mohou mít definované atributy vlastností obsahu, které pro rozšíření značek XAML znamenají, že se název vlastnosti nemusí zobrazovat. Vlastnost Name
je vlastností obsahu pro rozšíření x:Reference
a vlastnost Path
je vlastností obsahu pro Binding
, což znamená, že je možné odebrat je z výrazů:
<Label Text="TEXT"
FontSize="80"
HorizontalOptions="Center"
VerticalOptions="CenterAndExpand"
BindingContext="{x:Reference slider}"
Rotation="{Binding Value}" />
Vazby bez kontextu
Vlastnost BindingContext
je důležitou součástí datových vazeb, ale není vždy nezbytná. Zdrojový objekt se dá místo toho zadat ve volání SetBinding
nebo v rozšíření značek Binding
.
To je znázorněné v ukázce Alternative Code Binding (Alternativní vazba v kódu). Soubor XAML je podobný ukázce Basic Code Binding. Rozdílem je, že objekt Slider
je definovaný pro řízení vlastnosti Scale
objektu Label
. Z tohoto důvodu Slider
je nastavena pro rozsah -2 až 2:
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="DataBindingDemos.AlternativeCodeBindingPage"
Title="Alternative Code Binding">
<StackLayout Padding="10, 0">
<Label x:Name="label"
Text="TEXT"
FontSize="40"
HorizontalOptions="Center"
VerticalOptions="CenterAndExpand" />
<Slider x:Name="slider"
Minimum="-2"
Maximum="2"
VerticalOptions="CenterAndExpand" />
</StackLayout>
</ContentPage>
Soubor kódu na pozadí nastaví vazbu pomocí metody SetBinding
definované ve třídě BindableObject
. Argument je konstruktorem pro třídu Binding
:
public partial class AlternativeCodeBindingPage : ContentPage
{
public AlternativeCodeBindingPage()
{
InitializeComponent();
label.SetBinding(Label.ScaleProperty, new Binding("Value", source: slider));
}
}
Konstruktor Binding
má 6 parametrů, takže parametr source
je zadaný pojmenovaným argumentem. Argumentem je objekt slider
.
Spuštění tohoto programu může mít trochu překvapivý výsledek:
Na obrazovce systému iOS na levé straně jde vidět, jak obrazovka vypadá při prvním zobrazení stránky. Kde je objekt Label
?
Problémem je, že objekt Slider
má počáteční hodnotu 0. To způsobí, že vlastnost Scale
objektu Label
se také nastaví na hodnotu 0 a přepíše se výchozí hodnota 1. To vede k tomu, že objekt Label
je zpočátku neviditelný. Jak ukazuje snímek obrazovky v systému Android, můžete úpravou objektu Slider
objekt Label
znovu zviditelnit, ale jeho počáteční zmizení je znepokojivé.
V dalším článku zjistíte, jak se můžete tomuto problému vyhnout inicializací objektu Slider
z výchozí hodnoty vlastnosti Scale
.
Poznámka:
Třída VisualElement
definuje také vlastnosti ScaleX
a ScaleY
, které můžou měnit měřítko objektu VisualElement
odlišně ve vodorovném a svislém směru.
Stránka Alternative XAML Binding (Alternativní vazba v XAML) ukazuje ekvivalentní vazbu zcela v jazyce XAML:
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="DataBindingDemos.AlternativeXamlBindingPage"
Title="Alternative XAML Binding">
<StackLayout Padding="10, 0">
<Label Text="TEXT"
FontSize="40"
HorizontalOptions="Center"
VerticalOptions="CenterAndExpand"
Scale="{Binding Source={x:Reference slider},
Path=Value}" />
<Slider x:Name="slider"
Minimum="-2"
Maximum="2"
VerticalOptions="CenterAndExpand" />
</StackLayout>
</ContentPage>
Rozšíření značek Binding
má teď nastavené dvě vlastnosti oddělené čárkou: Source
a Path
. Pokud chcete, můžou být na stejném řádku:
Scale="{Binding Source={x:Reference slider}, Path=Value}" />
Vlastnost Source
je nastavená na vložené rozšíření značek x:Reference
, které má jinak stejnou syntaxi jako nastavení BindingContext
. Všimněte si, že ve složených závorkách nejsou žádné uvozovky a že tyto dvě vlastnosti musí být oddělené čárkou.
Vlastností obsahu rozšíření značek Binding
je vlastnost Path
, ale část Path=
v rozšíření značek je možné odebrat jenom v případě, že se jedná o první vlastnost ve výrazu. Pokud chcete část Path=
odebrat, musíte prohodit pořadí těchto dvou vlastností:
Scale="{Binding Value, Source={x:Reference slider}}" />
Přestože rozšíření značek XAML jsou obvykle oddělená složenými závorkami, můžou být také vyjádřená jako objektové elementy:
<Label Text="TEXT"
FontSize="40"
HorizontalOptions="Center"
VerticalOptions="CenterAndExpand">
<Label.Scale>
<Binding Source="{x:Reference slider}"
Path="Value" />
</Label.Scale>
</Label>
Nyní jsou Source
vlastnosti Path
běžné atributy XAML: Hodnoty se zobrazí v uvozovkách a atributy nejsou oddělené čárkou. Rozšíření značek x:Reference
se může také stát objektovým elementem:
<Label Text="TEXT"
FontSize="40"
HorizontalOptions="Center"
VerticalOptions="CenterAndExpand">
<Label.Scale>
<Binding Path="Value">
<Binding.Source>
<x:Reference Name="slider" />
</Binding.Source>
</Binding>
</Label.Scale>
</Label>
Tato syntaxe není obvyklá, ale v některých případech je potřebná při práci s komplexními objekty.
Prozatím uvedené příklady nastavují vlastnost BindingContext
a vlastnost Source
objektu Binding
na rozšíření značek x:Reference
a slouží jako odkaz na jiné zobrazení na stránce. Tyto dvě vlastnosti jsou typu Object
a můžou se nastavit na libovolný objekt, který obsahuje vlastnosti vhodné pro zdroje vazeb.
V dalších článcích zjistíte, že můžete nastavit vlastnost BindingContext
nebo Source
na rozšíření značek x:Static
, aby odkazovalo na hodnotu statické vlastnosti nebo pole, nebo na rozšíření značek StaticResource
pro odkazování na objekt uložený ve slovníku prostředků nebo přímo na objekt, který je obvykle (ale ne vždy) instancí třídy ViewModel.
Vlastnost BindingContext
je také možné nastavit na objekt Binding
, aby vlastnosti Source
a Path
objektu Binding
definovaly kontext vazby.
Dědičnost kontextu vazby
V tomto článku jste viděli, že zdrojový objekt můžete zadat pomocí vlastnosti BindingContext
nebo pomocí vlastnosti Source
objektu Binding
. Pokud jsou nastavené obě dvě, má vlastnost Source
objektu Binding
přednost před vlastností BindingContext
.
Vlastnost BindingContext
má velmi důležitou charakteristiku:
Nastavení vlastnosti BindingContext
se dědí prostřednictvím vizuálního stromu.
Jak vidíte, může to být velmi užitečné pro zjednodušení vazeb výrazů, a v některých případech – zejména ve scénářích MVVM (Model-View-ViewModel) – je nezbytné.
Ukázka Binding Context Inheritance (Dědičnost kontextu vazby) je jednoduchou ukázkou dědičnosti kontextu vazby:
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="DataBindingDemos.BindingContextInheritancePage"
Title="BindingContext Inheritance">
<StackLayout Padding="10">
<StackLayout VerticalOptions="FillAndExpand"
BindingContext="{x:Reference slider}">
<Label Text="TEXT"
FontSize="80"
HorizontalOptions="Center"
VerticalOptions="EndAndExpand"
Rotation="{Binding Value}" />
<BoxView Color="#800000FF"
WidthRequest="180"
HeightRequest="40"
HorizontalOptions="Center"
VerticalOptions="StartAndExpand"
Rotation="{Binding Value}" />
</StackLayout>
<Slider x:Name="slider"
Maximum="360" />
</StackLayout>
</ContentPage>
Vlastnost BindingContext
objektu StackLayout
je nastavená na objekt slider
. Tento kontext vazby dědí objekt Label
i BoxView
a oba mají své vlastnosti Rotation
nastavené na vlastnost Value
objektu Slider
:
V dalším článku uvidíte, jak může režim vazby změnit tok dat mezi cílovými a zdrojovými objekty.