4. část: Základy datových vazeb

Download Sample Stažení ukázky

Datové vazby umožňují propojení vlastností dvou objektů tak, aby změna v jednom způsobí změnu v druhém objektu. Jedná se o velmi cenný nástroj a zatímco datové vazby je možné definovat zcela v kódu, XAML poskytuje klávesové zkratky a pohodlí. V důsledku toho je jedním z nejdůležitějších rozšíření značek v Xamarin.Forms binding.

Datové vazby

Datové vazby spojují vlastnosti dvou objektů, označovaných jako zdroj a cíl. V kódu jsou vyžadovány dva kroky: Vlastnost BindingContext cílového objektu musí být nastavena na zdrojový objekt a SetBinding metoda (často použitá ve spojení s Binding třídou) musí být volána v cílovém objektu, aby bylo možné svázat vlastnost tohoto objektu s vlastností zdrojového objektu.

Cílová vlastnost musí být vlastnost svázatelná, což znamená, že cílový objekt musí být odvozen od BindableObject. Online Xamarin.Forms dokumentace označuje, které vlastnosti jsou vlastnosti s možností vazby. Vlastnost Label , jako Text je přidružena k vázání vlastnosti TextProperty.

V kódu musíte také provést stejné dva kroky, které jsou požadovány v kódu, s tím rozdílem, že Binding rozšíření revizí provádí místo SetBinding volání a Binding třídy.

Když však definujete datové vazby v XAML, existuje několik způsobů, jak nastavit BindingContext cílový objekt. Někdy se nastavuje ze souboru kódu, někdy používá příponu StaticResource nebo x:Static značku a někdy jako obsah BindingContext značek vlastností.

Vazby se nejčastěji používají k propojení vizuálů programu s podkladovým datovým modelem, obvykle při realizaci architektury aplikace MVVM (Model-View-ViewModel), jak je popsáno v části 5. Z datových vazeb na MVVM, ale další scénáře jsou možné.

Vazby zobrazení na zobrazení

Datové vazby můžete definovat pro propojení vlastností dvou zobrazení na stejné stránce. V tomto případě nastavíte BindingContext cílový objekt pomocí x:Reference rozšíření značek.

Tady je soubor XAML, který obsahuje Slider dvě Label zobrazení, z nichž jedna je otočena Slider hodnotou a jinou, která zobrazuje Slider hodnotu:

<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             x:Class="XamlSamples.SliderBindingsPage"
             Title="Slider Bindings Page">

    <StackLayout>
        <Label Text="ROTATION"
               BindingContext="{x:Reference Name=slider}"
               Rotation="{Binding Path=Value}"
               FontAttributes="Bold"
               FontSize="Large"
               HorizontalOptions="Center"
               VerticalOptions="CenterAndExpand" />

        <Slider x:Name="slider"
                Maximum="360"
                VerticalOptions="CenterAndExpand" />

        <Label BindingContext="{x:Reference slider}"
               Text="{Binding Value, StringFormat='The angle is {0:F0} degrees'}"
               FontAttributes="Bold"
               FontSize="Large"
               HorizontalOptions="Center"
               VerticalOptions="CenterAndExpand" />
    </StackLayout>
</ContentPage>

Obsahuje Sliderx:Name atribut odkazovaný dvěma Label zobrazeními pomocí x:Reference rozšíření značek.

Rozšíření x:Reference vazby definuje vlastnost pojmenovanou Name pro nastavení na název odkazovaného prvku, v tomto případě slider. Nicméně třída ReferenceExtension , která definuje x:Reference rozšíření značek také definuje ContentProperty atribut pro Name, což znamená, že není explicitně požadován. Jen pro řadu, první x:Reference obsahuje "Name=", ale druhý ne:

BindingContext="{x:Reference Name=slider}"
…
BindingContext="{x:Reference slider}"

Samotné Binding rozšíření značek může mít několik vlastností, stejně jako u BindingBase třídy a Binding třídy. Hodnota ContentProperty for Binding je Path, ale část "Path=" rozšíření značek může být vynechána, pokud je cesta první položkou Binding v rozšíření značek. První příklad obsahuje "Path=", ale druhý příklad ho vynechá:

Rotation="{Binding Path=Value}"
…
Text="{Binding Value, StringFormat='The angle is {0:F0} degrees'}"

Všechny vlastnosti můžou být na jednom řádku nebo oddělené na více řádcích:

Text="{Binding Value,
               StringFormat='The angle is {0:F0} degrees'}"

Udělejte to, co je pohodlné.

StringFormat Všimněte si vlastnosti ve druhém Binding rozšíření značek. Vazby Xamarin.Formsneprovádějí žádné implicitní převody typů, a pokud potřebujete zobrazit neřetězcový objekt jako řetězec, musíte zadat převaděč typů nebo použít StringFormat. Na pozadí se statická String.Format metoda používá k implementaci StringFormat. To může být problém, protože specifikace formátování .NET zahrnují složené závorky, které se také používají k oddělovači rozšíření značek. To vytváří riziko matoucího analyzátoru XAML. Abyste tomu předešli, vložte celý formátovací řetězec do jednoduchých uvozovek:

Text="{Binding Value, StringFormat='The angle is {0:F0} degrees'}"

Tady je spuštěný program:

View-to-View Bindings

Režim vazby

Jedno zobrazení může mít datové vazby na několik jeho vlastností. Každé zobrazení však může mít pouze jedno BindingContext, takže více datových vazeb v daném zobrazení musí všechny odkazovat vlastnosti stejného objektu.

Řešení tohoto a dalších problémů zahrnuje Mode vlastnost, která je nastavena na člen výčtu BindingMode :

  • Default
  • OneWay — hodnoty se přenesou ze zdroje do cíle.
  • OneWayToSource — hodnoty se přenesou z cíle do zdroje.
  • TwoWay — hodnoty jsou přeneseny oběma způsoby mezi zdrojem a cílem.
  • OneTime — data pocházejí ze zdroje do cíle, ale pouze v případě, že se BindingContext změny změní

Následující program ukazuje jedno běžné použití OneWayToSource režimů vazby.TwoWay Čtyři Slider zobrazení jsou určena k řízení Scale, Rotate, RotateXa RotateY vlastnosti Label. Zpočátku se zdá, že tyto čtyři vlastnosti Label by měly být cíle datové vazby, protože každá z nich je nastavena pomocí Slider. Může BindingContextLabel však být pouze jeden objekt a existují čtyři různé posuvníky.

Z tohoto důvodu jsou všechny vazby nastaveny zdánlivě zpětně: BindingContext Každý ze čtyř posuvníků je nastaven na Labelhodnotu a vazby jsou nastaveny na Value vlastnosti posuvníků. Pomocí a OneWayToSourceTwoWay režimů mohou tyto Value vlastnosti nastavit zdrojové vlastnosti, které jsou Scale, Rotate, RotateXa RotateY vlastnosti Label:

<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             x:Class="XamlSamples.SliderTransformsPage"
             Padding="5"
             Title="Slider Transforms Page">
    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition Height="*" />
            <RowDefinition Height="Auto" />
            <RowDefinition Height="Auto" />
            <RowDefinition Height="Auto" />
            <RowDefinition Height="Auto" />
        </Grid.RowDefinitions>

        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="*" />
            <ColumnDefinition Width="Auto" />
        </Grid.ColumnDefinitions>

        <!-- Scaled and rotated Label -->
        <Label x:Name="label"
               Text="TEXT"
               HorizontalOptions="Center"
               VerticalOptions="CenterAndExpand" />

        <!-- Slider and identifying Label for Scale -->
        <Slider x:Name="scaleSlider"
                BindingContext="{x:Reference label}"
                Grid.Row="1" Grid.Column="0"
                Maximum="10"
                Value="{Binding Scale, Mode=TwoWay}" />

        <Label BindingContext="{x:Reference scaleSlider}"
               Text="{Binding Value, StringFormat='Scale = {0:F1}'}"
               Grid.Row="1" Grid.Column="1"
               VerticalTextAlignment="Center" />

        <!-- Slider and identifying Label for Rotation -->
        <Slider x:Name="rotationSlider"
                BindingContext="{x:Reference label}"
                Grid.Row="2" Grid.Column="0"
                Maximum="360"
                Value="{Binding Rotation, Mode=OneWayToSource}" />

        <Label BindingContext="{x:Reference rotationSlider}"
               Text="{Binding Value, StringFormat='Rotation = {0:F0}'}"
               Grid.Row="2" Grid.Column="1"
               VerticalTextAlignment="Center" />

        <!-- Slider and identifying Label for RotationX -->
        <Slider x:Name="rotationXSlider"
                BindingContext="{x:Reference label}"
                Grid.Row="3" Grid.Column="0"
                Maximum="360"
                Value="{Binding RotationX, Mode=OneWayToSource}" />

        <Label BindingContext="{x:Reference rotationXSlider}"
               Text="{Binding Value, StringFormat='RotationX = {0:F0}'}"
               Grid.Row="3" Grid.Column="1"
               VerticalTextAlignment="Center" />

        <!-- Slider and identifying Label for RotationY -->
        <Slider x:Name="rotationYSlider"
                BindingContext="{x:Reference label}"
                Grid.Row="4" Grid.Column="0"
                Maximum="360"
                Value="{Binding RotationY, Mode=OneWayToSource}" />

        <Label BindingContext="{x:Reference rotationYSlider}"
               Text="{Binding Value, StringFormat='RotationY = {0:F0}'}"
               Grid.Row="4" Grid.Column="1"
               VerticalTextAlignment="Center" />
    </Grid>
</ContentPage>

Vazby na třech zobrazeních jsou OneWayToSource, což znamená, že Slider hodnota způsobí změnu vlastnosti jeho BindingContext, což je pojmenovaný Labellabel.Slider Tato tři Slider zobrazení způsobují změny v objektu Rotate, RotateXa RotateY vlastnosti Label.

Vazba pro Scale vlastnost je TwoWayvšak . Důvodem je to, že Scale vlastnost má výchozí hodnotu 1 a použití vazby TwoWay způsobí Slider , že počáteční hodnota bude nastavena na hodnotu 1 místo 0. Pokud by tato vazba byla OneWayToSource, Scale vlastnost by byla zpočátku nastavena na hodnotu 0 z Slider výchozí hodnoty. Tato Label možnost by nebyla viditelná a to může uživateli způsobit nejasnost.

Backwards Bindings

Poznámka:

Třída VisualElement má také vlastnostiScaleY, které škáluje VisualElement na ose ScaleX x a y.

Vazby a kolekce

Nic ilustruje výkon XAML a datových vazeb lépe než šablona .ListView

ListViewItemsSource definuje vlastnost typu IEnumerablea zobrazí položky v této kolekci. Tyto položky mohou být objekty libovolného typu. Ve výchozím nastavení ListView používá metodu ToString každé položky k zobrazení této položky. Někdy je to jen to, ToString co chcete, ale v mnoha případech vrátí pouze plně kvalifikovaný název třídy objektu.

Položky v ListView kolekci lze však zobrazit libovolným způsobem prostřednictvím šablony, která zahrnuje třídu odvozenou z Cell. Šablona se naklonuje pro každou položku v objektu ListViewa datové vazby nastavené v šabloně se přenesou do jednotlivých klonů.

Velmi často budete chtít vytvořit vlastní buňku ViewCell pro tyto položky pomocí třídy. Tento proces je v kódu poněkud nepořádný, ale v XAML se stává velmi jednoduchým.

Součástí projektu XamlSamples je třída s názvem NamedColor. Každý NamedColor objekt má Name a FriendlyName vlastnosti typu stringa Color vlastnost typu Color. Kromě toho NamedColor má 141 statických polí typu Color jen pro čtení odpovídajících barvám definovaným Xamarin.FormsColor ve třídě. Statický konstruktor vytvoří IEnumerable<NamedColor> kolekci obsahující NamedColor objekty odpovídající těmto statickým polím a přiřadí ji k jeho veřejné statické All vlastnosti.

Nastavení statické NamedColor.All vlastnosti na ItemsSource značek ListView je snadné pomocí x:Static rozšíření značek:

<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             xmlns:local="clr-namespace:XamlSamples;assembly=XamlSamples"
             x:Class="XamlSamples.ListViewDemoPage"
             Title="ListView Demo Page">

    <ListView ItemsSource="{x:Static local:NamedColor.All}" />

</ContentPage>

Výsledný displej určuje, že položky jsou skutečně typu XamlSamples.NamedColor:

Binding to a Collection

Není to moc informací, ale je možné ho ListView posunout a vybrat.

Chcete-li definovat šablonu pro položky, budete chtít rozdělit ItemTemplate vlastnost jako prvek vlastnosti a nastavit ji na hodnotu DataTemplate, která pak odkazuje na ViewCell. View Pro vlastnost ViewCell můžete definovat rozložení jednoho nebo více zobrazení pro zobrazení každé položky. Tady je jednoduchý příklad:

<ListView ItemsSource="{x:Static local:NamedColor.All}">
    <ListView.ItemTemplate>
        <DataTemplate>
            <ViewCell>
                <ViewCell.View>
                    <Label Text="{Binding FriendlyName}" />
                </ViewCell.View>
            </ViewCell>
        </DataTemplate>
    </ListView.ItemTemplate>
</ListView>

Poznámka:

Zdroj vazby pro buňky a podřízené buňky je ListView.ItemsSource kolekce.

Element Label je nastaven na View vlastnost ViewCell. (Značky ViewCell.View nejsou potřeba, protože View vlastnost je vlastnost ViewCellobsahu .) Tento kód zobrazí vlastnost každého NamedColor objektuFriendlyName:

Binding to a Collection with a DataTemplate

Mnohem lepší. Vše, co je teď potřeba, je namáčknout šablonu položky s dalšími informacemi a skutečnou barvou. Pro podporu této šablony byly některé hodnoty a objekty definovány ve slovníku prostředků stránky:

<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             xmlns:local="clr-namespace:XamlSamples"
             x:Class="XamlSamples.ListViewDemoPage"
             Title="ListView Demo Page">

    <ContentPage.Resources>
        <ResourceDictionary>
            <OnPlatform x:Key="boxSize"
                        x:TypeArguments="x:Double">
                <On Platform="iOS, Android, UWP" Value="50" />
            </OnPlatform>

            <OnPlatform x:Key="rowHeight"
                        x:TypeArguments="x:Int32">
                <On Platform="iOS, Android, UWP" Value="60" />
            </OnPlatform>

            <local:DoubleToIntConverter x:Key="intConverter" />

        </ResourceDictionary>
    </ContentPage.Resources>

    <ListView ItemsSource="{x:Static local:NamedColor.All}"
              RowHeight="{StaticResource rowHeight}">
        <ListView.ItemTemplate>
            <DataTemplate>
                <ViewCell>
                    <StackLayout Padding="5, 5, 0, 5"
                                 Orientation="Horizontal"
                                 Spacing="15">

                        <BoxView WidthRequest="{StaticResource boxSize}"
                                 HeightRequest="{StaticResource boxSize}"
                                 Color="{Binding Color}" />

                        <StackLayout Padding="5, 0, 0, 0"
                                     VerticalOptions="Center">

                            <Label Text="{Binding FriendlyName}"
                                   FontAttributes="Bold"
                                   FontSize="Medium" />

                            <StackLayout Orientation="Horizontal"
                                         Spacing="0">
                                <Label Text="{Binding Color.R,
                                       Converter={StaticResource intConverter},
                                       ConverterParameter=255,
                                       StringFormat='R={0:X2}'}" />

                                <Label Text="{Binding Color.G,
                                       Converter={StaticResource intConverter},
                                       ConverterParameter=255,
                                       StringFormat=', G={0:X2}'}" />

                                <Label Text="{Binding Color.B,
                                       Converter={StaticResource intConverter},
                                       ConverterParameter=255,
                                       StringFormat=', B={0:X2}'}" />
                            </StackLayout>
                        </StackLayout>
                    </StackLayout>
                </ViewCell>
            </DataTemplate>
        </ListView.ItemTemplate>
    </ListView>
</ContentPage>

Všimněte si použití OnPlatform k definování velikosti BoxView a výšky ListView řádků. I když jsou hodnoty pro všechny platformy stejné, značky by se daly snadno přizpůsobit pro další hodnoty, aby bylo možné vyladit zobrazení.

Převaděče hodnot vazeb

Předchozí ListView Demo XAML soubor zobrazí jednotlivé R, Ga B vlastnosti Xamarin.FormsColor struktury. Tyto vlastnosti jsou typu a jsou v rozsahu double od 0 do 1. Pokud chcete zobrazit šestnáctkové hodnoty, nemůžete jednoduše použít StringFormat se specifikací formátování "X2". To funguje pouze pro celá čísla a kromě toho, double hodnoty musí být vynásobeny 255.

Tento malý problém byl vyřešen pomocí převaděče hodnot, označovaný také jako převaděč vazby. Toto je třída, která implementuje IValueConverter rozhraní, což znamená, že má dvě metody pojmenované Convert a ConvertBack. Metoda Convert se volá, když je hodnota přenesena ze zdroje do cíle; ConvertBack metoda se volá pro přenosy z cíle do zdroje nebo OneWayToSourceTwoWay vazby:

using System;
using System.Globalization;
using Xamarin.Forms;

namespace XamlSamples
{
    class DoubleToIntConverter : IValueConverter
    {
        public object Convert(object value, Type targetType,
                              object parameter, CultureInfo culture)
        {
            double multiplier;

            if (!Double.TryParse(parameter as string, out multiplier))
                multiplier = 1;

            return (int)Math.Round(multiplier * (double)value);
        }

        public object ConvertBack(object value, Type targetType,
                                  object parameter, CultureInfo culture)
        {
            double divider;

            if (!Double.TryParse(parameter as string, out divider))
                divider = 1;

            return ((double)(int)value) / divider;
        }
    }
}

Metoda ConvertBack v tomto programu nehraje roli, protože vazby jsou pouze jedním ze zdroje do cíle.

Vazba odkazuje na převaděč vazby Converter s vlastností. Převaděč vazeb může také přijmout parametr zadaný s ConverterParameter vlastností. Pro určitou všestrannost je to způsob určení násobitele. Převaděč vazeb zkontroluje, zda parametr převaděče obsahuje platnou double hodnotu.

Převaděč se vytvoří instance ve slovníku prostředků, takže ho lze sdílet mezi několika vazbami:

<local:DoubleToIntConverter x:Key="intConverter" />

Na tuto jednu instanci odkazují tři datové vazby. Všimněte si, že Binding rozšíření značek obsahuje vložené StaticResource rozšíření značek:

<Label Text="{Binding Color.R,
                      Converter={StaticResource intConverter},
                      ConverterParameter=255,
                      StringFormat='R={0:X2}'}" />

Tady je výsledek:

Binding to a Collection with a DataTemplate and Converters

Jedná se ListView o poměrně sofistikované zpracování změn, které se můžou dynamicky vyskytovat v podkladových datech, ale pouze v případě, že provedete určité kroky. Pokud kolekce položek přiřazených k ItemsSource vlastnosti ListView změn během běhu – to znamená, že pokud lze položky přidat nebo odebrat z kolekce , použijte ObservableCollection pro tyto položky třídu. ObservableCollection implementuje INotifyCollectionChanged rozhraní a ListView nainstaluje obslužnou rutinu CollectionChanged události.

Pokud se vlastnosti samotných položek mění během běhu, měly by položky v kolekci implementovat rozhraní a signalizovat INotifyPropertyChanged změny hodnot vlastností pomocí PropertyChanged události. To je znázorněno v další části této série, část 5. Z datové vazby na MVVM.

Shrnutí

Datové vazby poskytují výkonný mechanismus pro propojení vlastností mezi dvěma objekty na stránce nebo mezi vizuálními objekty a podkladovými daty. Když ale aplikace začne pracovat se zdroji dat, začíná se jako užitečný paradigma objevit oblíbený vzor architektury aplikace. To je popsáno v části 5. Z datových vazeb na MVVM.