Bölüm 4. Temel Veri Bağlama Bilgileri

Veri bağlamaları, iki nesnenin özelliklerinin bağlanmasına izin verir, böylece bir nesnedeki bir değişiklik diğerinde değişikliğe neden olur. Bu çok değerli bir araçtır ve veri bağlamaları tamamen kodda tanımlanabilirken, XAML kısayollar ve kolaylık sağlar. Sonuç olarak, içindeki Xamarin.Forms en önemli işaretleme uzantılarından biri Bağlama'dır.

Veri Bağlamaları

Veri bağlamaları, kaynak ve hedef olarak adlandırılan iki nesnenin özelliklerini bağlar. Kodda iki adım gerekir: BindingContext Hedef nesnenin özelliği kaynak nesneye ayarlanmalıdır ve SetBinding bu nesnenin bir özelliğini kaynak nesnenin özelliğine bağlamak için hedef nesnede yöntemi (genellikle sınıfla Binding birlikte kullanılır) çağrılmalıdır.

Hedef özelliği bağlanabilir bir özellik olmalıdır, bu da hedef nesnenin öğesinden BindableObjecttüretilmesi gerektiği anlamına gelir. Çevrimiçi Xamarin.Forms belgeler, hangi özelliklerin bağlanabilir özellikler olduğunu gösterir. gibi Text bir Label özelliği, bağlanabilir özelliğiyle TextPropertyilişkilendirilir.

İşaretlemeyi yaparken, işaretleme uzantısının çağrının ve Binding sınıfın yerini SetBinding alması dışında Binding kodda gerekli olan iki adımı da gerçekleştirmeniz gerekir.

Ancak, XAML'de veri bağlamaları tanımladığınızda, hedef nesnenin ayarlanmasının BindingContext birden çok yolu vardır. Bazen arka planda kod dosyasından, bazen bir StaticResource veya x:Static işaretleme uzantısı kullanılarak, bazen de özellik öğesi etiketlerinin BindingContext içeriği olarak ayarlanır.

Bağlamalar en sık, Bölüm 5'te açıklandığı gibi MVVM (Model-View-ViewModel) uygulama mimarisinin gerçekleştirilmesinde bir programın görsellerini temel alınan veri modeline bağlamak için kullanılır. Veri Bağlamalarından MVVM'ye, ancak diğer senaryolar mümkündür.

Görünümden Görünüme Bağlamalar

Aynı sayfadaki iki görünümün özelliklerini bağlamak için veri bağlamaları tanımlayabilirsiniz. Bu durumda, işaretleme uzantısını kullanarak hedef nesnenin x:Reference değerini ayarlarsınızBindingContext.

Aşağıda, biri değer tarafından Slider döndürülen ve diğeri değeri görüntüleyen bir Slider ve iki Label görünüm içeren bir XAML dosyası yer alırSlider:

<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>

, Slider işaretleme uzantısı kullanılarak iki Label görünüm tarafından başvuruda bulunan x:Reference bir x:Name öznitelik içerir.

Bağlama x:Reference uzantısı, bu örnekte sliderbaşvuruda bulunan öğesinin adına ayarlamak için adlı Name bir özellik tanımlar. Ancak, ReferenceExtension işaretleme uzantısını x:Reference tanımlayan sınıf için Namebir ContentProperty özniteliği de tanımlar; bu da açıkça gerekli olmadığı anlamına gelir. Yalnızca çeşitlilik için, ilki x:Reference "Name=" içerir, ancak ikincisi şunları içermez:

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

İşaretlemeyi Binding uzantısının kendisi de ve Binding sınıfı gibi çeşitli özelliklere BindingBase sahip olabilir. ContentProperty için Binding şeklindedirPath, ancak yol işaretleme uzantısındaki ilk öğeyseBinding, işaretleme uzantısının "Path=" bölümü atlanabilir. İlk örnekte "Path=" var, ancak ikinci örnek bunu atlar:

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

Özelliklerin tümü bir satırda veya birden çok satıra ayrılabilir:

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

Uygun olan her şeyi yap.

StringFormat İkinci Binding işaretleme uzantısında özelliğine dikkat edin. içinde Xamarin.Formsbağlamalar örtük tür dönüştürmeleri gerçekleştirmez ve dize olmayan bir nesneyi dize olarak görüntülemeniz gerekiyorsa bir tür dönüştürücüsü sağlamanız veya kullanmanız StringFormatgerekir. Arka planda, statik String.Format yöntemi uygulamak StringFormatiçin kullanılır. .NET biçimlendirme belirtimleri, işaretleme uzantılarını sınırlandırmak için de kullanılan küme ayraçları içerdiğinden, bu büyük olasılıkla bir sorundur. Bu, XAML ayrıştırıcısını karıştırma riski oluşturur. Bunu önlemek için biçimlendirme dizesinin tamamını tek tırnak içine alın:

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

Çalışan program şu şekildedir:

Görünümden Görünüme Bağlamalar

Bağlama Modu

Tek bir görünümde, özelliklerinin birkaçı üzerinde veri bağlamaları olabilir. Ancak, her görünümde yalnızca bir BindingContextolabilir, bu nedenle bu görünümdeki birden çok veri bağlaması aynı nesnenin tüm başvuru özelliklerine sahip olmalıdır.

Bu ve diğer sorunların çözümü, numaralandırmanın Mode bir üyesine BindingMode ayarlanan özelliği içerir:

  • Default
  • OneWay — değerler kaynaktan hedefe aktarılır
  • OneWayToSource — değerler hedeften kaynağa aktarılır
  • TwoWay — değerler hem kaynak hem de hedef arasında aktarılır
  • OneTime — veriler kaynaktan hedefe gider, ancak yalnızca BindingContext değişiklikler

Aşağıdaki program, ve TwoWay bağlama modlarının OneWayToSource yaygın kullanımlarından birini gösterir. Dört Slider görünüm, bir Labelöğesinin Scale, Rotate, RotateXve RotateY özelliklerini denetlemek için tasarlanmıştır. İlk başta, her biri tarafından Sliderayarlandığı için bu dört özelliğinin Label veri bağlama hedefleri olması gerekir gibi görünüyor. Ancak , BindingContext Label yalnızca bir nesne olabilir ve dört farklı kaydırıcı vardır.

Bu nedenle, tüm bağlamalar görünüşte geriye dönük olarak ayarlanır: BindingContext Dört kaydırıcının her biri değerine ayarlanır Labelve bağlamalar kaydırıcıların özelliklerine Value göre ayarlanır. ve modlarını OneWayToSource kullanarak, bu Value özellikler , , RotateXve RotateY özellikleri olan ScaleRotatekaynak özelliklerini Labelayarlayabilir:TwoWay

<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>

Görünümlerin üçindeki Slider bağlamalar şeklindedirOneWayToSource, yani Slider değeri adlı labelöğesinin BindingContextözelliğinde değişikliğe neden olurLabel. Bu üç Slider görünüm, içinde , RotateXve RotateY özelliklerinde değişikliklere RotateLabelneden olur.

Ancak, özelliğinin bağlaması Scale olur TwoWay. Bunun nedeni, özelliğin Scale varsayılan değeri 1 olması ve bağlama kullanılması TwoWay ilk değerin Slider 0 yerine 1 olarak ayarlanmasına neden olmasıdır. Bu bağlama olsaydı OneWayToSourceScale özelliği başlangıçta varsayılan değerden Slider 0 olarak ayarlanırdı. Label görünür olmayacaktır ve bu durum kullanıcının kafa karışıklığına neden olabilir.

Geriye Dönük Bağlamalar

Not

Sınıfın VisualElement ayrıca ve özellikleri vardır ScaleX ve ScaleY bu özellikler sırasıyla x ekseni ve y ekseni üzerinde ölçeklendirilir VisualElement .

Bağlamalar ve Koleksiyonlar

Hiçbir şey XAML'nin gücünü ve veri bağlamalarını şablonlu değerinden daha iyi gösterelememektedir ListView.

ListViewtüründe IEnumerablebir ItemsSource özellik tanımlar ve bu koleksiyondaki öğeleri görüntüler. Bu öğeler herhangi bir türde nesneler olabilir. Varsayılan olarak, ListView bu öğeyi ToString görüntülemek için her öğenin yöntemini kullanır. Bazen istediğiniz şey bu olsa da çoğu durumda ToString nesnenin yalnızca tam sınıf adını döndürür.

Ancak koleksiyondaki ListView öğeler, öğesinden Celltüretilen bir sınıfı içeren bir şablon kullanarak istediğiniz şekilde görüntülenebilir. Şablon içindeki ListViewher öğe için kopyalanır ve şablonda ayarlanan veri bağlamaları tek tek kopyalara aktarılır.

Çoğu zaman sınıfını kullanarak ViewCell bu öğeler için özel bir hücre oluşturmak istersiniz. Bu işlem kodda biraz karmaşıktır, ancak XAML'de çok basit hale gelir.

XamlSamples projesine dahil edilen adlı bir sınıftır NamedColor. Her NamedColor nesnenin türü stringve FriendlyName özellikleri ve türünde Colorbir Color özelliği vardırName. Ayrıca, NamedColor sınıfında tanımlanan Xamarin.FormsColor renklere karşılık gelen türdeki 141 statik salt okunur alanı Color vardır. Statik oluşturucu, bu statik alanlara karşılık gelen nesneleri içeren NamedColor bir IEnumerable<NamedColor> koleksiyon oluşturur ve bunu genel statik All özelliğine atar.

İşaretlemeyi ItemsSource kullanarak x:Static statik NamedColor.All özelliğin ListView değerine ayarlanması kolaydır:

<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>

Sonuçta elde edilen görüntü, öğelerin gerçekten türünde XamlSamples.NamedColorolduğunu belirler:

Koleksiyona Bağlama

Bu çok fazla bilgi değildir, ancak ListView kaydırılabilir ve seçilebilir.

Öğeler için bir şablon tanımlamak için özelliği bir özellik öğesi olarak ayırmak ItemTemplate ve bunu olarak DataTemplateayarlamak ve ardından öğesine ViewCellbaşvurmak isteyeceksiniz. View özelliğinin özelliğineViewCell, her öğeyi görüntülemek için bir veya daha fazla görünümün düzenini tanımlayabilirsiniz. İşte basit bir örnek:

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

Not

Hücrelerin ve hücrelerin alt öğelerinin bağlama kaynağı koleksiyondur ListView.ItemsSource .

Label öğesi öğesinin View özelliğine ViewCellayarlanır. (özelliği öğesinin ViewCell.View View içerik özelliği ViewCellolduğundan etiketler gerekli değildir.) Bu işaretleme her NamedColor nesnenin FriendlyName özelliğini görüntüler:

DataTemplate ile Bir Koleksiyona Bağlama

Çok daha iyi. Artık tek gereken, öğe şablonunu daha fazla bilgi ve gerçek renkle ladinlendirmektir. Bu şablonu desteklemek için sayfanın kaynak sözlüğünde bazı değerler ve nesneler tanımlanmıştır:

<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>

bir boyutunu ve satırların BoxView yüksekliğini tanımlamak için kullanımına OnPlatform ListView dikkat edin. Tüm platformların değerleri aynı olsa da, işaretleme diğer değerlere göre kolayca uyarlanabilir ve ekranda ince ayar yapılabilir.

Bağlama Değeri Dönüştürücüleri

Önceki ListView Demo XAML dosyası, yapının tek tek R, Gve B özelliklerini Xamarin.FormsColor görüntüler. Bu özellikler türündedir double ve 0 ile 1 arasındadır. Onaltılık değerleri görüntülemek istiyorsanız, yalnızca "X2" biçimlendirme belirtimi ile kullanamazsınız StringFormat . Bu yalnızca tamsayılar için geçerlidir ve bunun yanı sıra, değerlerin double 255 ile çarpılması gerekir.

Bu küçük sorun, bağlama dönüştürücüsü olarak da adlandırılan bir değer dönüştürücüsü ile çözüldü. Bu, ve adlı Convert ConvertBackiki yöntemi olduğu anlamına gelen arabirimini uygulayan IValueConverter bir sınıftır. Bir Convert değer kaynaktan hedefe aktarıldığında yöntemi çağrılır; ConvertBack veya bağlamalarında OneWayToSource TwoWay hedeften kaynağa aktarımlar için yöntemi çağrılır:

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;
        }
    }
}

ConvertBack Bağlamalar kaynaktan hedefe yalnızca bir yol olduğundan yöntemi bu programda rol oynamaz.

Bağlama, özelliğiyle bir bağlama dönüştürücüsünü başvurur Converter . Bağlama dönüştürücüsü özelliğiyle belirtilen bir parametreyi ConverterParameter de kabul edebilir. Çok yönlülük için çarpan bu şekilde belirtilir. Bağlama dönüştürücüsü, dönüştürücü parametresini geçerli double bir değer için denetler.

Dönüştürücü, birden çok bağlama arasında paylaşılabilmesi için kaynak sözlüğünde örneği oluşturulur:

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

Üç veri bağlaması bu tek örneğe başvurur. İşaretlemeyi uzantısının Binding eklenmiş StaticResource bir işaretleme uzantısı içerdiğine dikkat edin:

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

Sonuç şu şekildedir:

DataTemplate ve Dönüştürücülerle Bir Koleksiyona Bağlama

ListView, yalnızca belirli adımları uygulamanız durumunda temel alınan verilerde dinamik olarak gerçekleşebilecek değişiklikleri işleme konusunda oldukça karmaşıktır. Çalışma zamanı sırasında değişikliklerin özelliğine ListView atanan öğe koleksiyonu (yani koleksiyona ItemsSource öğe eklenebiliyorsa veya koleksiyondan kaldırılabiliyorsa), bu öğeler için bir ObservableCollection sınıf kullanın. ObservableCollection arabirimini INotifyCollectionChanged uygular ve ListView olay için CollectionChanged bir işleyici yükler.

Çalışma zamanı sırasında öğelerin özellikleri değişirse, koleksiyondaki öğeler arabirimini uygulamalı INotifyPropertyChanged ve olayı kullanarak özellik değerlerine değişiklik sinyali vermelidir PropertyChanged . Bu, bu serinin sonraki bölümü olan Bölüm 5'te gösterilmiştir. Veri Bağlama'dan MVVM'ye.

Özet

Veri bağlamaları, bir sayfadaki iki nesne arasında veya görsel nesnelerle temel alınan veriler arasında özellikleri bağlamak için güçlü bir mekanizma sağlar. Ancak uygulama veri kaynaklarıyla çalışmaya başladığında, popüler bir uygulama mimari düzeni yararlı bir paradigma olarak ortaya çıkmaya başlar. Bu, Bölüm 5'te ele alınmıştır. Veri Bağlamalarından MVVM'ye.