Udostępnij za pośrednictwem


Xamarin.Forms Tryb powiązania

W poprzednim artykule alternatywne powiązania kodu i alternatywne powiązania XAML zawierały element Label z właściwością Scale powiązaną Value z właściwością Slider. Ponieważ początkowa Slider wartość to 0, spowodowało Scale to ustawienie właściwości Label 0, a nie 1, a Label zniknęło.

Strona Powiązanie odwrotne jest podobna do programów w poprzednim artykule, z tą różnicą, że powiązanie danych jest definiowane na Slider zamiast w pliku Label:

<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             x:Class="DataBindingDemos.ReverseBindingPage"
             Title="Reverse Binding">
    <StackLayout Padding="10, 0">

        <Label x:Name="label"
               Text="TEXT"
               FontSize="80"
               HorizontalOptions="Center"
               VerticalOptions="CenterAndExpand" />

        <Slider x:Name="slider"
                VerticalOptions="CenterAndExpand"
                Value="{Binding Source={x:Reference label},
                                Path=Opacity}" />
    </StackLayout>
</ContentPage>

Na początku może się to wydawać wstecz: teraz Label jest to źródło powiązania danych, a Slider element jest obiektem docelowym. Powiązanie odwołuje się do Opacity właściwości Label, która ma wartość domyślną 1.

Jak można się spodziewać, parametr Slider jest inicjowany do wartości 1 z początkowej Opacity Labelwartości . Jest to wyświetlane na zrzucie ekranu systemu iOS po lewej stronie:

Powiązanie odwrotne

Ale może być zaskoczony, że Slider nadal działa, jak pokazuje zrzut ekranu systemu Android. Wydaje się, że powiązanie danych działa lepiej, gdy Slider element docelowy powiązania jest elementem docelowym powiązania, a nie Label dlatego, że inicjowanie działa tak, jak możemy się spodziewać.

Różnica między przykładem odwrotnego powiązania a wcześniejszymi przykładami obejmuje tryb powiązania.

Domyślny tryb powiązania

Tryb powiązania jest określony z elementem członkowskim BindingMode wyliczenia:

  • Default
  • TwoWay — dane idą w obie strony między źródłem a obiektem docelowym
  • OneWay — dane przechodzą ze źródła do miejsca docelowego
  • OneWayToSource — dane przechodzą z miejsca docelowego do źródła
  • OneTime — dane przechodzą ze źródła do miejsca docelowego, ale tylko wtedy, gdy BindingContext zmiany (nowe z wersją Xamarin.Forms 3.0)

Każda właściwość powiązana ma domyślny tryb powiązania, który jest ustawiany podczas tworzenia właściwości możliwej do powiązania i która jest dostępna z DefaultBindingMode właściwości BindableProperty obiektu. Ten domyślny tryb powiązania wskazuje tryb obowiązujący, gdy ta właściwość jest obiektem docelowym powiązania danych.

Domyślny tryb powiązania dla większości właściwości, takich jak Rotation, Scalei Opacity to OneWay. Gdy te właściwości są obiektami docelowymi powiązania danych, właściwość docelowa jest ustawiana ze źródła.

Jednak domyślnym trybem powiązania dla Value właściwości elementu Slider jest TwoWay. Oznacza to, że gdy Value właściwość jest obiektem docelowym powiązania danych, element docelowy jest ustawiany ze źródła (jak zwykle), ale źródło jest również ustawione z obiektu docelowego. Umożliwia to ustawienie wartości Slider początkowej Opacity .

To powiązanie dwukierunkowe może wydawać się tworzenie nieskończonej pętli, ale tak się nie dzieje. Właściwości możliwe do powiązania nie sygnalizują zmiany właściwości, chyba że właściwość rzeczywiście ulegnie zmianie. Zapobiega to nieskończonej pętli.

Powiązania dwukierunkowe

Większość właściwości możliwych do powiązania ma domyślny tryb powiązania, OneWay ale następujące właściwości mają domyślny tryb TwoWaypowiązania :

  • Date właściwość DatePicker
  • TextEditorwłaściwość , , EntrySearchBariEntryCell
  • IsRefreshing właściwość ListView
  • SelectedItem właściwość MultiPage
  • SelectedIndexwłaściwości i SelectedItemPicker
  • Valuewłaściwość i SliderStepper
  • IsToggled właściwość Switch
  • On właściwość SwitchCell
  • Time właściwość TimePicker

Te konkretne właściwości są definiowane jako TwoWay bardzo dobry powód:

Gdy powiązania danych są używane z architekturą aplikacji Model-View-ViewModel (MVVM), klasa ViewModel jest źródłem powiązania danych, a widok, który składa się z widoków, takich jak Slider, są obiektami docelowymi powiązania danych. Powiązania MVVM przypominają przykład Odwrotne powiązanie więcej niż powiązania w poprzednich przykładach. Bardzo prawdopodobne jest, że każdy widok na stronie ma zostać zainicjowany z wartością odpowiedniej właściwości w modelu ViewModel, ale zmiany w widoku powinny również mieć wpływ na właściwość ViewModel.

Właściwości z domyślnymi trybami TwoWay powiązania to te właściwości, które najprawdopodobniej będą używane w scenariuszach MVVM.

Powiązania jednokierunkowe do źródła

Właściwości możliwe do powiązania tylko do odczytu mają domyślny tryb OneWayToSourcepowiązania . Istnieje tylko jedna właściwość do odczytu/zapisu, która ma domyślny tryb OneWayToSourcepowiązania :

  • SelectedItem właściwość ListView

Uzasadnieniem jest to, że powiązanie właściwości SelectedItem powinno spowodować ustawienie źródła powiązania. Przykład w dalszej części tego artykułu zastępuje to zachowanie.

Powiązania jednorazowe

Kilka właściwości ma domyślny tryb OneTimepowiązania , w tym IsTextPredictionEnabled właściwość Entry.

Właściwości docelowe z trybem OneTime powiązania są aktualizowane tylko wtedy, gdy kontekst powiązania ulegnie zmianie. W przypadku powiązań dla tych właściwości docelowych upraszcza to infrastrukturę powiązania, ponieważ nie jest konieczne monitorowanie zmian we właściwościach źródłowych.

ViewModels and Property-Change Notifications

Na stronie Selektor kolorów prostych przedstawiono użycie prostego modelu ViewModel. Powiązania danych umożliwiają użytkownikowi wybranie koloru przy użyciu trzech Slider elementów odcieni, nasycenia i jasności.

Model ViewModel jest źródłem powiązania danych. Model ViewModel nie definiuje właściwości możliwych do powiązania, ale implementuje mechanizm powiadomień, który umożliwia powiadamianie infrastruktury powiązania, gdy wartość właściwości ulegnie zmianie. Ten mechanizm powiadomień jest interfejsem INotifyPropertyChanged , który definiuje jedno zdarzenie o nazwie PropertyChanged. Klasa, która implementuje ten interfejs, zwykle uruchamia zdarzenie, gdy jedna z jego właściwości publicznych zmienia wartość. Zdarzenie nie musi być uruchamiane, jeśli właściwość nigdy się nie zmienia. (Interfejs INotifyPropertyChanged jest również implementowany przez BindableObject program i PropertyChanged zdarzenie jest wyzwalane za każdym razem, gdy właściwość, którą można powiązać zmienia wartość).

Klasa HslColorViewModel definiuje pięć właściwości: Huewłaściwości , SaturationLuminosity, i Color są powiązane. Gdy którykolwiek z trzech składników kolorów zmienia wartość, Color właściwość jest ponownie obliczana, a PropertyChanged zdarzenia są wyzwalane dla wszystkich czterech właściwości:

public class HslColorViewModel : INotifyPropertyChanged
{
    Color color;
    string name;

    public event PropertyChangedEventHandler PropertyChanged;

    public double Hue
    {
        set
        {
            if (color.Hue != value)
            {
                Color = Color.FromHsla(value, color.Saturation, color.Luminosity);
            }
        }
        get
        {
            return color.Hue;
        }
    }

    public double Saturation
    {
        set
        {
            if (color.Saturation != value)
            {
                Color = Color.FromHsla(color.Hue, value, color.Luminosity);
            }
        }
        get
        {
            return color.Saturation;
        }
    }

    public double Luminosity
    {
        set
        {
            if (color.Luminosity != value)
            {
                Color = Color.FromHsla(color.Hue, color.Saturation, value);
            }
        }
        get
        {
            return color.Luminosity;
        }
    }

    public Color Color
    {
        set
        {
            if (color != value)
            {
                color = value;
                PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("Hue"));
                PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("Saturation"));
                PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("Luminosity"));
                PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("Color"));

                Name = NamedColor.GetNearestColorName(color);
            }
        }
        get
        {
            return color;
        }
    }

    public string Name
    {
        private set
        {
            if (name != value)
            {
                name = value;
                PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("Name"));
            }
        }
        get
        {
            return name;
        }
    }
}

Color Gdy właściwość ulegnie zmianie, metoda statyczna GetNearestColorName w NamedColor klasie (również uwzględniona w rozwiązaniu DataBindingDemos) uzyskuje najbliższy nazwany kolor i ustawia Name właściwość. Ta Name właściwość ma prywatną set metodę dostępu, więc nie można jej ustawić spoza klasy.

Gdy model ViewModel jest ustawiony jako źródło powiązania, infrastruktura powiązania dołącza procedurę obsługi do PropertyChanged zdarzenia. W ten sposób powiązanie może zostać powiadomione o zmianach właściwości, a następnie ustawić właściwości docelowe ze zmienionych wartości.

Jednak jeśli właściwość docelowa (lub Binding definicja we właściwości docelowej) ma BindingMode OneTimewartość , nie jest konieczne, aby infrastruktura powiązania dołączała program obsługi w PropertyChanged zdarzeniu. Właściwość docelowa jest aktualizowana tylko wtedy, gdy BindingContext zmienia się, a nie wtedy, gdy sama właściwość źródłowa ulegnie zmianie.

Plik XAML selektora prostego koloru tworzy wystąpienie HslColorViewModel w słowniku zasobów strony i inicjuje Color właściwość. Właściwość BindingContext Grid właściwości jest ustawiona na StaticResource rozszerzenie powiązania, aby odwoływać się do tego zasobu:

<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             xmlns:local="clr-namespace:DataBindingDemos"
             x:Class="DataBindingDemos.SimpleColorSelectorPage">

    <ContentPage.Resources>
        <ResourceDictionary>
            <local:HslColorViewModel x:Key="viewModel"
                                     Color="MediumTurquoise" />

            <Style TargetType="Slider">
                <Setter Property="VerticalOptions" Value="CenterAndExpand" />
            </Style>
        </ResourceDictionary>
    </ContentPage.Resources>

    <Grid BindingContext="{StaticResource viewModel}">
        <Grid.RowDefinitions>
            <RowDefinition Height="*" />
            <RowDefinition Height="*" />
        </Grid.RowDefinitions>

        <BoxView Color="{Binding Color}"
                 Grid.Row="0" />

        <StackLayout Grid.Row="1"
                     Margin="10, 0">

            <Label Text="{Binding Name}"
                   HorizontalTextAlignment="Center" />

            <Slider Value="{Binding Hue}" />

            <Slider Value="{Binding Saturation}" />

            <Slider Value="{Binding Luminosity}" />
        </StackLayout>
    </Grid>
</ContentPage>

Widoki BoxView, Labeli trzy Slider dziedziczą kontekst powiązania z klasy Grid. Te widoki to wszystkie obiekty docelowe powiązania odwołujące się do właściwości źródła w modelu ViewModel. Color Dla właściwości BoxView, i Text właściwości Label, powiązania danych to OneWay: Właściwości w widoku są ustawione z właściwości w Modelu Widok.

Właściwość Value , jednak ma TwoWaywartość Slider. Umożliwia to ustawienie każdego Slider elementu z modelu ViewModel, a także ustawienie modelu ViewModel z każdego Sliderelementu .

Po pierwszym uruchomieniu programu wszystkie BoxViewelementy , Labeli trzy Slider elementy są ustawione z modelu ViewModel na podstawie początkowej Color właściwości ustawionej podczas tworzenia wystąpienia modelu ViewModel. Jest to wyświetlane na zrzucie ekranu systemu iOS po lewej stronie:

Selektor kolorów prostych

W miarę manipulowania suwakami kontrolki BoxView i Label są odpowiednio aktualizowane, jak pokazano na zrzucie ekranu systemu Android.

Utworzenie wystąpienia modelu ViewModel w słowniku zasobów jest jednym z typowych podejść. Istnieje również możliwość utworzenia wystąpienia elementu ViewModel w tagach elementu właściwości dla BindingContext właściwości. W pliku XAML selektora kolorów prostych spróbuj usunąć HslColorViewModel element ze słownika zasobów i ustawić go na właściwość podobną do BindingContext następującejGrid:

<Grid>
    <Grid.BindingContext>
        <local:HslColorViewModel Color="MediumTurquoise" />
    </Grid.BindingContext>

    ···

</Grid>

Kontekst powiązania można ustawić na różne sposoby. Czasami plik w tle tworzy wystąpienie elementu ViewModel i ustawia go na BindingContext właściwość strony. Są to wszystkie prawidłowe podejścia.

Zastępowanie trybu powiązania

Jeśli domyślny tryb powiązania we właściwości docelowej nie jest odpowiedni dla określonego powiązania danych, można go zastąpić, ustawiając Mode właściwość (lub Mode właściwość Binding Binding rozszerzenia znaczników) na jeden z elementów członkowskich BindingMode wyliczenia.

Jednak ustawienie Mode właściwości na TwoWay wartość nie zawsze działa zgodnie z oczekiwaniami. Na przykład spróbuj zmodyfikować alternatywny plik XAML powiązania XAML, aby uwzględnić TwoWay go w definicji powiązania:

<Label Text="TEXT"
       FontSize="40"
       HorizontalOptions="Center"
       VerticalOptions="CenterAndExpand"
       Scale="{Binding Source={x:Reference slider},
                       Path=Value,
                       Mode=TwoWay}" />

Może się spodziewać, że Slider właściwość zostanie zainicjowana do początkowej Scale wartości właściwości, czyli 1, ale tak się nie stanie. TwoWay Po zainicjowaniu powiązania element docelowy jest ustawiany z pierwszego źródła, co oznacza, że Scale właściwość jest ustawiona na wartość domyślną Slider 0. TwoWay Gdy powiązanie jest ustawione na Sliderobiekcie , Slider element jest początkowo ustawiany ze źródła.

Tryb powiązania można ustawić OneWayToSource na w przykładzie Alternatywne powiązanie XAML:

<Label Text="TEXT"
       FontSize="40"
       HorizontalOptions="Center"
       VerticalOptions="CenterAndExpand"
       Scale="{Binding Source={x:Reference slider},
                       Path=Value,
                       Mode=OneWayToSource}" />

Teraz parametr Slider jest inicjowany na 1 (wartość Scaledomyślna ) ale manipulowanie Slider właściwością nie ma wpływu na Scale właściwość, więc nie jest to bardzo przydatne.

Uwaga

Klasa VisualElement definiuje również właściwości ScaleX i ScaleY, które umożliwiają skalowanie klasy VisualElement w różny sposób poziomo i pionowo.

Bardzo przydatna aplikacja zastępowania domyślnego trybu powiązania z TwoWay właściwością SelectedItem ListView. Domyślnym trybem powiązania jest OneWayToSource. Po ustawieniu powiązania danych we SelectedItem właściwości w celu odwołania się do właściwości źródłowej w modelu ViewModel ta właściwość źródłowa jest ustawiana z zaznaczenia ListView . Jednak w niektórych okolicznościach można również zainicjować element ListView z modelu ViewModel.

Na stronie Przykładowe ustawienia przedstawiono tę technikę. Ta strona reprezentuje prostą implementację ustawień aplikacji, które są bardzo często zdefiniowane w modelu ViewModel, na przykład w tym SampleSettingsViewModel pliku:

public class SampleSettingsViewModel : INotifyPropertyChanged
{
    string name;
    DateTime birthDate;
    bool codesInCSharp;
    double numberOfCopies;
    NamedColor backgroundNamedColor;

    public event PropertyChangedEventHandler PropertyChanged;

    public SampleSettingsViewModel(IDictionary<string, object> dictionary)
    {
        Name = GetDictionaryEntry<string>(dictionary, "Name");
        BirthDate = GetDictionaryEntry(dictionary, "BirthDate", new DateTime(1980, 1, 1));
        CodesInCSharp = GetDictionaryEntry<bool>(dictionary, "CodesInCSharp");
        NumberOfCopies = GetDictionaryEntry(dictionary, "NumberOfCopies", 1.0);
        BackgroundNamedColor = NamedColor.Find(GetDictionaryEntry(dictionary, "BackgroundNamedColor", "White"));
    }

    public string Name
    {
        set { SetProperty(ref name, value); }
        get { return name; }
    }

    public DateTime BirthDate
    {
        set { SetProperty(ref birthDate, value); }
        get { return birthDate; }
    }

    public bool CodesInCSharp
    {
        set { SetProperty(ref codesInCSharp, value); }
        get { return codesInCSharp; }
    }

    public double NumberOfCopies
    {
        set { SetProperty(ref numberOfCopies, value); }
        get { return numberOfCopies; }
    }

    public NamedColor BackgroundNamedColor
    {
        set
        {
            if (SetProperty(ref backgroundNamedColor, value))
            {
                OnPropertyChanged("BackgroundColor");
            }
        }
        get { return backgroundNamedColor; }
    }

    public Color BackgroundColor
    {
        get { return BackgroundNamedColor?.Color ?? Color.White; }
    }

    public void SaveState(IDictionary<string, object> dictionary)
    {
        dictionary["Name"] = Name;
        dictionary["BirthDate"] = BirthDate;
        dictionary["CodesInCSharp"] = CodesInCSharp;
        dictionary["NumberOfCopies"] = NumberOfCopies;
        dictionary["BackgroundNamedColor"] = BackgroundNamedColor.Name;
    }

    T GetDictionaryEntry<T>(IDictionary<string, object> dictionary, string key, T defaultValue = default(T))
    {
        return dictionary.ContainsKey(key) ? (T)dictionary[key] : defaultValue;
    }

    bool SetProperty<T>(ref T storage, T value, [CallerMemberName] string propertyName = null)
    {
        if (object.Equals(storage, value))
            return false;

        storage = value;
        OnPropertyChanged(propertyName);
        return true;
    }

    protected void OnPropertyChanged([CallerMemberName] string propertyName = null)
    {
        PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
    }
}

Każde ustawienie aplikacji jest właściwością zapisaną w słowniku Xamarin.Forms właściwości w metodzie o nazwie SaveState i załadowanej z tego słownika w konstruktorze. W dolnej części klasy są dwie metody, które ułatwiają usprawnianie modelu ViewModel i sprawiają, że są one mniej podatne na błędy. Metoda OnPropertyChanged w dolnej części zawiera opcjonalny parametr, który jest ustawiony na właściwość wywołującą. Pozwala to uniknąć błędów pisowni podczas określania nazwy właściwości jako ciągu.

Metoda SetProperty w klasie robi jeszcze więcej: porównuje wartość, która jest ustawiana na właściwość z wartością przechowywaną jako pole, i wywołuje OnPropertyChanged tylko wtedy, gdy dwie wartości nie są równe.

Klasa SampleSettingsViewModel definiuje dwie właściwości koloru tła: BackgroundNamedColor właściwość jest typu NamedColor, która jest również klasą zawartą w rozwiązaniu DataBindingDemos . Właściwość BackgroundColor jest typu Colori jest uzyskiwana z Color właściwości NamedColor obiektu.

Klasa NamedColor używa odbicia platformy .NET w celu wyliczenia wszystkich statycznych pól publicznych w Xamarin.FormsColor strukturze i przechowywania ich nazw w kolekcji dostępnej z właściwości statycznej All :

public class NamedColor : IEquatable<NamedColor>, IComparable<NamedColor>
{
    // Instance members
    private NamedColor()
    {
    }

    public string Name { private set; get; }

    public string FriendlyName { private set; get; }

    public Color Color { private set; get; }

    public string RgbDisplay { private set; get; }

    public bool Equals(NamedColor other)
    {
        return Name.Equals(other.Name);
    }

    public int CompareTo(NamedColor other)
    {
        return Name.CompareTo(other.Name);
    }

    // Static members
    static NamedColor()
    {
        List<NamedColor> all = new List<NamedColor>();
        StringBuilder stringBuilder = new StringBuilder();

        // Loop through the public static fields of the Color structure.
        foreach (FieldInfo fieldInfo in typeof(Color).GetRuntimeFields())
        {
            if (fieldInfo.IsPublic &&
                fieldInfo.IsStatic &&
                fieldInfo.FieldType == typeof(Color))
            {
                // Convert the name to a friendly name.
                string name = fieldInfo.Name;
                stringBuilder.Clear();
                int index = 0;

                foreach (char ch in name)
                {
                    if (index != 0 && Char.IsUpper(ch))
                    {
                        stringBuilder.Append(' ');
                    }
                    stringBuilder.Append(ch);
                    index++;
                }

                // Instantiate a NamedColor object.
                Color color = (Color)fieldInfo.GetValue(null);

                NamedColor namedColor = new NamedColor
                {
                    Name = name,
                    FriendlyName = stringBuilder.ToString(),
                    Color = color,
                    RgbDisplay = String.Format("{0:X2}-{1:X2}-{2:X2}",
                                                (int)(255 * color.R),
                                                (int)(255 * color.G),
                                                (int)(255 * color.B))
                };

                // Add it to the collection.
                all.Add(namedColor);
            }
        }
        all.TrimExcess();
        all.Sort();
        All = all;
    }

    public static IList<NamedColor> All { private set; get; }

    public static NamedColor Find(string name)
    {
        return ((List<NamedColor>)All).Find(nc => nc.Name == name);
    }

    public static string GetNearestColorName(Color color)
    {
        double shortestDistance = 1000;
        NamedColor closestColor = null;

        foreach (NamedColor namedColor in NamedColor.All)
        {
            double distance = Math.Sqrt(Math.Pow(color.R - namedColor.Color.R, 2) +
                                        Math.Pow(color.G - namedColor.Color.G, 2) +
                                        Math.Pow(color.B - namedColor.Color.B, 2));

            if (distance < shortestDistance)
            {
                shortestDistance = distance;
                closestColor = namedColor;
            }
        }
        return closestColor.Name;
    }
}

Klasa App w projekcie DataBindingDemos definiuje właściwość o nazwie Settings typu SampleSettingsViewModel. Ta właściwość jest inicjowana po utworzeniu App wystąpienia klasy, a SaveState metoda jest wywoływana, gdy metoda jest wywoływana OnSleep :

public partial class App : Application
{
    public App()
    {
        InitializeComponent();

        Settings = new SampleSettingsViewModel(Current.Properties);

        MainPage = new NavigationPage(new MainPage());
    }

    public SampleSettingsViewModel Settings { private set; get; }

    protected override void OnStart()
    {
        // Handle when your app starts
    }

    protected override void OnSleep()
    {
        // Handle when your app sleeps
        Settings.SaveState(Current.Properties);
    }

    protected override void OnResume()
    {
        // Handle when your app resumes
    }
}

Aby uzyskać więcej informacji na temat metod cyklu życia aplikacji, zobacz artykuł Cykl życia aplikacji.

Prawie wszystkie inne elementy są obsługiwane w pliku SampleSettingsPage.xaml . Strona BindingContext jest ustawiana przy użyciu Binding rozszerzenia znaczników: źródło powiązania jest właściwością statyczną Application.Current , która jest wystąpieniem App klasy w projekcie, a Path właściwość jest ustawiona na Settings właściwość , która jest obiektem SampleSettingsViewModel :

<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             xmlns:local="clr-namespace:DataBindingDemos"
             x:Class="DataBindingDemos.SampleSettingsPage"
             Title="Sample Settings"
             BindingContext="{Binding Source={x:Static Application.Current},
                                      Path=Settings}">

    <StackLayout BackgroundColor="{Binding BackgroundColor}"
                 Padding="10"
                 Spacing="10">

        <StackLayout Orientation="Horizontal">
            <Label Text="Name: "
                   VerticalOptions="Center" />

            <Entry Text="{Binding Name}"
                   Placeholder="your name"
                   HorizontalOptions="FillAndExpand"
                   VerticalOptions="Center" />
        </StackLayout>

        <StackLayout Orientation="Horizontal">
            <Label Text="Birth Date: "
                   VerticalOptions="Center" />

            <DatePicker Date="{Binding BirthDate}"
                        HorizontalOptions="FillAndExpand"
                        VerticalOptions="Center" />
        </StackLayout>

        <StackLayout Orientation="Horizontal">
            <Label Text="Do you code in C#? "
                   VerticalOptions="Center" />

            <Switch IsToggled="{Binding CodesInCSharp}"
                    VerticalOptions="Center" />
        </StackLayout>

        <StackLayout Orientation="Horizontal">
            <Label Text="Number of Copies: "
                   VerticalOptions="Center" />

            <Stepper Value="{Binding NumberOfCopies}"
                     VerticalOptions="Center" />

            <Label Text="{Binding NumberOfCopies}"
                   VerticalOptions="Center" />
        </StackLayout>

        <Label Text="Background Color:" />

        <ListView x:Name="colorListView"
                  ItemsSource="{x:Static local:NamedColor.All}"
                  SelectedItem="{Binding BackgroundNamedColor, Mode=TwoWay}"
                  VerticalOptions="FillAndExpand"
                  RowHeight="40">
            <ListView.ItemTemplate>
                <DataTemplate>
                    <ViewCell>
                        <StackLayout Orientation="Horizontal">
                            <BoxView Color="{Binding Color}"
                                     HeightRequest="32"
                                     WidthRequest="32"
                                     VerticalOptions="Center" />

                            <Label Text="{Binding FriendlyName}"
                                   FontSize="24"
                                   VerticalOptions="Center" />
                        </StackLayout>                        
                    </ViewCell>
                </DataTemplate>
            </ListView.ItemTemplate>
        </ListView>
    </StackLayout>
</ContentPage>

Wszystkie elementy podrzędne strony dziedziczą kontekst powiązania. Większość innych powiązań na tej stronie to właściwości w pliku SampleSettingsViewModel. Właściwość BackgroundColor służy do ustawiania BackgroundColor właściwości StackLayout, a Entrywłaściwości , DatePickerSwitch, i Stepper są powiązane z innymi właściwościami w modelu ViewModel.

Właściwość ItemsSource właściwości ListView jest ustawiona na właściwość statyczną NamedColor.All . Spowoduje to wypełnienie ListView wszystkich NamedColor wystąpień. Dla każdego elementu w elemencie ListViewkontekst powiązania dla elementu jest ustawiony na NamedColor obiekt. Wartości BoxView i Label w obiekcie ViewCell są powiązane z właściwościami w pliku NamedColor.

Właściwość SelectedItem typu , i jest powiązana z właściwością BackgroundNamedColor SampleSettingsViewModel:NamedColorListView

SelectedItem="{Binding BackgroundNamedColor, Mode=TwoWay}"

Domyślnym trybem powiązania dla SelectedItem elementu jest OneWayToSource, który ustawia właściwość ViewModel z wybranego elementu. Tryb TwoWay umożliwia SelectedItem zainicjowanie elementu z modelu ViewModel.

Jednak po ustawieniu elementu SelectedItem w ten sposób element nie jest automatycznie przewijany w ListView celu wyświetlenia wybranego elementu. Potrzebny jest mały kod w pliku za pomocą kodu:

public partial class SampleSettingsPage : ContentPage
{
    public SampleSettingsPage()
    {
        InitializeComponent();

        if (colorListView.SelectedItem != null)
        {
            colorListView.ScrollTo(colorListView.SelectedItem,
                                   ScrollToPosition.MakeVisible,
                                   false);
        }
    }
}

Zrzut ekranu systemu iOS po lewej stronie przedstawia program po pierwszym uruchomieniu. Konstruktor inicjuje SampleSettingsViewModel kolor tła na biały, a to, co jest zaznaczone w elemecie ListView:

Przykładowe ustawienia

Drugi zrzut ekranu przedstawia zmienione ustawienia. Podczas eksperymentowania z tą stroną pamiętaj, aby umieścić program w stanie uśpienia lub przerwać go na urządzeniu lub emulatorze, na którym jest uruchomiony. Zakończenie programu z debugera programu Visual Studio nie spowoduje OnSleep wywołania przesłonięcia w App klasie.

W następnym artykule zobaczysz, jak określić formatowanie ciągu powiązań danych ustawionych we Text właściwości Label.