Sdílet prostřednictvím


5. část: Od datových vazeb k MVVM

Model-View-ViewModel (MVVM) byl vynalezen s ohledem na XAML. Model vynucuje oddělení mezi třemi softwarovými vrstvami – uživatelským rozhraním XAML označovaným jako Zobrazení; podkladová data, označovaná jako model; a zprostředkovatelem mezi zobrazením a modelem, který se nazývá Model ViewModel. Zobrazení a model ViewModel jsou často propojeny prostřednictvím datových vazeb definovaných v souboru XAML. BindingContext pro zobrazení je obvykle instance Modelu ViewModel.

Jednoduchý model ViewModel

Jako úvod k modelu ViewModels se nejprve podíváme na program bez jednoho. Dříve jste viděli, jak definovat novou deklaraci oboru názvů XML, která umožňuje souboru XAML odkazovat na třídy v jiných sestaveních. Tady je program, který definuje deklaraci oboru názvů XML pro System obor názvů:

xmlns:sys="clr-namespace:System;assembly=netstandard"

Program může použít x:Static k získání aktuálního data a času ze statické DateTime.Now vlastnosti a nastavit tuto DateTime hodnotu na BindingContext hodnotu na :StackLayout

<StackLayout BindingContext="{x:Static sys:DateTime.Now}" …>

BindingContext je speciální vlastnost: Při nastavení elementu BindingContext je zděděna všemi podřízenými prvky tohoto prvku. To znamená, že všechny podřízené položky StackLayout mají stejné BindingContexta mohou obsahovat jednoduché vazby na vlastnosti tohoto objektu.

V programu One-Shot DateTime dva podřízené položky obsahují vazby na vlastnosti této DateTime hodnoty, ale dvě další podřízené položky obsahují vazby, které zdánlivě chybí cesta vazby. To znamená, že samotná DateTime hodnota se používá pro StringFormat:

<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             xmlns:sys="clr-namespace:System;assembly=netstandard"
             x:Class="XamlSamples.OneShotDateTimePage"
             Title="One-Shot DateTime Page">

    <StackLayout BindingContext="{x:Static sys:DateTime.Now}"
                 HorizontalOptions="Center"
                 VerticalOptions="Center">

        <Label Text="{Binding Year, StringFormat='The year is {0}'}" />
        <Label Text="{Binding StringFormat='The month is {0:MMMM}'}" />
        <Label Text="{Binding Day, StringFormat='The day is {0}'}" />
        <Label Text="{Binding StringFormat='The time is {0:T}'}" />

    </StackLayout>
</ContentPage>

Problém je, že datum a čas jsou nastaveny jednou při prvním sestavení stránky a nikdy se nezmění:

Zobrazení zobrazení data a času

Soubor XAML může zobrazit hodiny, které vždy zobrazují aktuální čas, ale potřebuje nějaký kód, který vám pomůže. Když uvažujete o MVVM, Model a ViewModel jsou třídy napsané zcela v kódu. Zobrazení je často soubor XAML, který odkazuje na vlastnosti definované v modelu ViewModel prostřednictvím datových vazeb.

Správný model je ignorant modelu ViewModel a správný Model ViewModel je ignorant zobrazení. Programátor ale často přizpůsobí datové typy vystavené modelem ViewModel datovým typům přidruženým ke konkrétním uživatelským rozhraním. Pokud například model přistupuje k databázi, která obsahuje 8bitové řetězce ASCII, model ViewModel by potřeboval převést mezi těmito řetězci na řetězce Unicode, aby vyhovoval výhradnímu použití unicode v uživatelském rozhraní.

Vjednoduchýchm modelech (MVVM) se v jednoduchých příkladech MVVM (například zde zobrazených) často žádný model vůbec nepoužívá a tento model zahrnuje pouze zobrazení a model ViewModel.

Tady je model ViewModel pro hodiny s pouze jednou vlastností s názvem DateTime, která aktualizuje danou DateTime vlastnost každou sekundu:

using System;
using System.ComponentModel;
using Xamarin.Forms;

namespace XamlSamples
{
    class ClockViewModel : INotifyPropertyChanged
    {
        DateTime dateTime;

        public event PropertyChangedEventHandler PropertyChanged;

        public ClockViewModel()
        {
            this.DateTime = DateTime.Now;

            Device.StartTimer(TimeSpan.FromSeconds(1), () =>
                {
                    this.DateTime = DateTime.Now;
                    return true;
                });
        }

        public DateTime DateTime
        {
            set
            {
                if (dateTime != value)
                {
                    dateTime = value;

                    if (PropertyChanged != null)
                    {
                        PropertyChanged(this, new PropertyChangedEventArgs("DateTime"));
                    }
                }
            }
            get
            {
                return dateTime;
            }
        }
    }
}

ViewModels obecně implementuje INotifyPropertyChanged rozhraní, což znamená, že třída aktivuje PropertyChanged událost vždy, když se změní jedna z jejích vlastností. Mechanismus datové vazby připevňuje Xamarin.Forms obslužnou rutinu k této PropertyChanged události, aby bylo možné upozornit, když se vlastnost změní a cíl se aktualizuje novou hodnotou.

Hodiny založené na tomto modelu ViewModel mohou být stejně jednoduché jako tyto:

<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.ClockPage"
             Title="Clock Page">

    <Label Text="{Binding DateTime, StringFormat='{0:T}'}"
           FontSize="Large"
           HorizontalOptions="Center"
           VerticalOptions="Center">
        <Label.BindingContext>
            <local:ClockViewModel />
        </Label.BindingContext>
    </Label>
</ContentPage>

Všimněte si, jak je nastavena ClockViewModel na BindingContext značky elementu Label property. Alternativně můžete vytvořit instanci ClockViewModel kolekce Resources a nastavit ji na BindingContext rozšíření prostřednictvím StaticResource značek. Nebo může soubor s kódem vytvořit instanci modelu ViewModel.

Rozšíření Binding značek u Text vlastnosti Label formátuje DateTime vlastnost. Tady je zobrazení:

Zobrazení zobrazení data a času pomocí modelu ViewModel

Přístup k jednotlivým vlastnostem objektu DateTime ViewModel je také možný tak, že vlastnosti oddělíte tečkami:

<Label Text="{Binding DateTime.Second, StringFormat='{0}'}" … >

Interaktivní virtuální počítač MVVM

MVVM se často používá s obousměrnými datovými vazbami pro interaktivní zobrazení na základě podkladového datového modelu.

Tady je třída s názvem HslViewModel , která převede Color hodnotu na Hue, Saturationa Luminosity hodnoty a naopak:

using System;
using System.ComponentModel;
using Xamarin.Forms;

namespace XamlSamples
{
    public class HslViewModel : INotifyPropertyChanged
    {
        double hue, saturation, luminosity;
        Color color;

        public event PropertyChangedEventHandler PropertyChanged;

        public double Hue
        {
            set
            {
                if (hue != value)
                {
                    hue = value;
                    OnPropertyChanged("Hue");
                    SetNewColor();
                }
            }
            get
            {
                return hue;
            }
        }

        public double Saturation
        {
            set
            {
                if (saturation != value)
                {
                    saturation = value;
                    OnPropertyChanged("Saturation");
                    SetNewColor();
                }
            }
            get
            {
                return saturation;
            }
        }

        public double Luminosity
        {
            set
            {
                if (luminosity != value)
                {
                    luminosity = value;
                    OnPropertyChanged("Luminosity");
                    SetNewColor();
                }
            }
            get
            {
                return luminosity;
            }
        }

        public Color Color
        {
            set
            {
                if (color != value)
                {
                    color = value;
                    OnPropertyChanged("Color");

                    Hue = value.Hue;
                    Saturation = value.Saturation;
                    Luminosity = value.Luminosity;
                }
            }
            get
            {
                return color;
            }
        }

        void SetNewColor()
        {
            Color = Color.FromHsla(Hue, Saturation, Luminosity);
        }

        protected virtual void OnPropertyChanged(string propertyName)
        {
            PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
        }
    }
}

Změny v objektu Hue, Saturationa Luminosity vlastnosti způsobí Color změnu vlastnosti a změny způsobí, že Color se ostatní tři vlastnosti změní. Může to vypadat jako nekonečná smyčka s tím rozdílem, že třída nevyvolá PropertyChanged událost, pokud se vlastnost nezměnila. Tím se ukončí jinak neovládnutelná smyčka zpětné vazby.

Následující soubor XAML obsahuje vlastnost BoxView , jejíž Color vlastnost je vázána na Color vlastnost ViewModel, a tři Slider a tři Label zobrazení svázané s Hue, Saturationa Luminosity vlastnosti:

<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.HslColorScrollPage"
             Title="HSL Color Scroll Page">
    <ContentPage.BindingContext>
        <local:HslViewModel Color="Aqua" />
    </ContentPage.BindingContext>

    <StackLayout Padding="10, 0">
        <BoxView Color="{Binding Color}"
                 VerticalOptions="FillAndExpand" />

        <Label Text="{Binding Hue, StringFormat='Hue = {0:F2}'}"
               HorizontalOptions="Center" />

        <Slider Value="{Binding Hue, Mode=TwoWay}" />

        <Label Text="{Binding Saturation, StringFormat='Saturation = {0:F2}'}"
               HorizontalOptions="Center" />

        <Slider Value="{Binding Saturation, Mode=TwoWay}" />

        <Label Text="{Binding Luminosity, StringFormat='Luminosity = {0:F2}'}"
               HorizontalOptions="Center" />

        <Slider Value="{Binding Luminosity, Mode=TwoWay}" />
    </StackLayout>
</ContentPage>

Vazba na každém z nich Label je výchozí OneWay. Jenom musí zobrazit hodnotu. Ale vazba na každém Slider z nich je TwoWay. To umožňuje Slider inicializaci z modelu ViewModel. Všimněte si, že Color vlastnost je nastavena Aqua při vytvoření instance Modelu ViewModel. Změna ale Slider musí také nastavit novou hodnotu vlastnosti v Modelu ViewModel, která pak vypočítá novou barvu.

MVVM s využitím obousměrných datových vazeb

Příkazování pomocí modelů ViewModels

V mnoha případech je model MVVM omezen na manipulaci s datovými položkami: Objekty uživatelského rozhraní v zobrazení paralelních datových objektů v Modelu ViewModel.

Někdy ale zobrazení musí obsahovat tlačítka, která aktivují různé akce v modelu ViewModel. Model ViewModel však nesmí obsahovat Clicked obslužné rutiny pro tlačítka, protože by to sváže model ViewModel s konkrétním paradigmatem uživatelského rozhraní.

Chcete-li povolit ViewModels být více nezávislý na konkrétních objektech uživatelského rozhraní, ale přesto povolit, aby metody být volány v rámci Modelu ViewModel, existuje příkazové rozhraní. Toto příkazové rozhraní je podporováno následujícími prvky v Xamarin.Forms:

  • Button
  • MenuItem
  • ToolbarItem
  • SearchBar
  • TextCell (a proto také ImageCell)
  • ListView
  • TapGestureRecognizer

S výjimkou elementu SearchBar a ListView elementu definují tyto prvky dvě vlastnosti:

  • Command typu System.Windows.Input.ICommand
  • CommandParameter typu Object

Definuje SearchBar a SearchCommandParameter vlastnosti, zatímco ListView definuje RefreshCommand vlastnost typu ICommand.SearchCommand

Rozhraní ICommand definuje dvě metody a jednu událost:

  • void Execute(object arg)
  • bool CanExecute(object arg)
  • event EventHandler CanExecuteChanged

Model ViewModel může definovat vlastnosti typu ICommand. Tyto vlastnosti pak můžete svázat s Command vlastností každého Button nebo druhého prvku, nebo možná vlastní zobrazení, které implementuje toto rozhraní. Volitelně můžete nastavit CommandParameter vlastnost pro identifikaci jednotlivých Button objektů (nebo jiných prvků), které jsou vázány na tuto ViewModel vlastnost. Interně volá metodu pokaždé, Button když uživatel klepne Button, předat Execute metodě jeho CommandParameter.Execute

Metoda CanExecute a CanExecuteChanged událost se používají v případech, kdy Button může být klepnutí aktuálně neplatné, v takovém případě Button by se měl sám zakázat. Volání ButtonCanExecute při Command prvním nastavení vlastnosti a při každém CanExecuteChanged spuštění události. Pokud CanExecute se vrátí false, Button zakáže se samotná a nevygeneruje Execute volání.

Nápovědu k přidání příkazů do modelu ViewModels Xamarin.Forms definuje dvě třídy, které implementují ICommand: Command a Command<T> kde T je typ argumentů a ExecuteCanExecute. Tyto dvě třídy definují několik konstruktorů a metodu ChangeCanExecute , kterou ViewModel může volat, aby objekt vynutil Command vyvolání CanExecuteChanged události.

Tady je model ViewModel pro jednoduchou klávesnici, která je určená pro zadávání telefonních čísel. Všimněte si, že v CanExecute konstruktoru Execute jsou funkce lambda definované jako funkce lambda:

using System;
using System.ComponentModel;
using System.Windows.Input;
using Xamarin.Forms;

namespace XamlSamples
{
    class KeypadViewModel : INotifyPropertyChanged
    {
        string inputString = "";
        string displayText = "";
        char[] specialChars = { '*', '#' };

        public event PropertyChangedEventHandler PropertyChanged;

        // Constructor
        public KeypadViewModel()
        {
            AddCharCommand = new Command<string>((key) =>
                {
                    // Add the key to the input string.
                    InputString += key;
                });

            DeleteCharCommand = new Command(() =>
                {
                    // Strip a character from the input string.
                    InputString = InputString.Substring(0, InputString.Length - 1);
                },
                () =>
                {
                    // Return true if there's something to delete.
                    return InputString.Length > 0;
                });
        }

        // Public properties
        public string InputString
        {
            protected set
            {
                if (inputString != value)
                {
                    inputString = value;
                    OnPropertyChanged("InputString");
                    DisplayText = FormatText(inputString);

                    // Perhaps the delete button must be enabled/disabled.
                    ((Command)DeleteCharCommand).ChangeCanExecute();
                }
            }

            get { return inputString; }
        }

        public string DisplayText
        {
            protected set
            {
                if (displayText != value)
                {
                    displayText = value;
                    OnPropertyChanged("DisplayText");
                }
            }
            get { return displayText; }
        }

        // ICommand implementations
        public ICommand AddCharCommand { protected set; get; }

        public ICommand DeleteCharCommand { protected set; get; }

        string FormatText(string str)
        {
            bool hasNonNumbers = str.IndexOfAny(specialChars) != -1;
            string formatted = str;

            if (hasNonNumbers || str.Length < 4 || str.Length > 10)
            {
            }
            else if (str.Length < 8)
            {
                formatted = String.Format("{0}-{1}",
                                          str.Substring(0, 3),
                                          str.Substring(3));
            }
            else
            {
                formatted = String.Format("({0}) {1}-{2}",
                                          str.Substring(0, 3),
                                          str.Substring(3, 3),
                                          str.Substring(6));
            }
            return formatted;
        }

        protected void OnPropertyChanged(string propertyName)
        {
            PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
        }
    }
}

Tento model ViewModel předpokládá, že AddCharCommand vlastnost je vázána na Command vlastnost několika tlačítek (nebo cokoli jiného, co má příkazové rozhraní), z nichž každá je identifikována CommandParameter. Tato tlačítka přidávají znaky do InputString vlastnosti, která se pak naformátuje jako telefonní číslo vlastnosti DisplayText .

Existuje také druhá vlastnost typu ICommand s názvem DeleteCharCommand. To je vázáno na tlačítko pro mezery zpět, ale tlačítko by mělo být zakázáno, pokud neexistují žádné znaky k odstranění.

Následující klávesnice není tak vizuálně sofistikovaná, jak by mohla. Místo toho byl redukován na minimum, aby bylo jasněji demonstrováno použití příkazového rozhraní:

<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.KeypadPage"
             Title="Keypad Page">

    <Grid HorizontalOptions="Center"
          VerticalOptions="Center">
        <Grid.BindingContext>
            <local:KeypadViewModel />
        </Grid.BindingContext>

        <Grid.RowDefinitions>
            <RowDefinition Height="Auto" />
            <RowDefinition Height="Auto" />
            <RowDefinition Height="Auto" />
            <RowDefinition Height="Auto" />
            <RowDefinition Height="Auto" />
        </Grid.RowDefinitions>

        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="80" />
            <ColumnDefinition Width="80" />
            <ColumnDefinition Width="80" />
        </Grid.ColumnDefinitions>

        <!-- Internal Grid for top row of items -->
        <Grid Grid.Row="0" Grid.Column="0" Grid.ColumnSpan="3">
            <Grid.ColumnDefinitions>
                <ColumnDefinition Width="*" />
                <ColumnDefinition Width="Auto" />
            </Grid.ColumnDefinitions>

            <Frame Grid.Column="0"
                   OutlineColor="Accent">
                <Label Text="{Binding DisplayText}" />
            </Frame>

            <Button Text="&#x21E6;"
                    Command="{Binding DeleteCharCommand}"
                    Grid.Column="1"
                    BorderWidth="0" />
        </Grid>

        <Button Text="1"
                Command="{Binding AddCharCommand}"
                CommandParameter="1"
                Grid.Row="1" Grid.Column="0" />

        <Button Text="2"
                Command="{Binding AddCharCommand}"
                CommandParameter="2"
                Grid.Row="1" Grid.Column="1" />

        <Button Text="3"
                Command="{Binding AddCharCommand}"
                CommandParameter="3"
                Grid.Row="1" Grid.Column="2" />

        <Button Text="4"
                Command="{Binding AddCharCommand}"
                CommandParameter="4"
                Grid.Row="2" Grid.Column="0" />

        <Button Text="5"
                Command="{Binding AddCharCommand}"
                CommandParameter="5"
                Grid.Row="2" Grid.Column="1" />

        <Button Text="6"
                Command="{Binding AddCharCommand}"
                CommandParameter="6"
                Grid.Row="2" Grid.Column="2" />

        <Button Text="7"
                Command="{Binding AddCharCommand}"
                CommandParameter="7"
                Grid.Row="3" Grid.Column="0" />

        <Button Text="8"
                Command="{Binding AddCharCommand}"
                CommandParameter="8"
                Grid.Row="3" Grid.Column="1" />

        <Button Text="9"
                Command="{Binding AddCharCommand}"
                CommandParameter="9"
                Grid.Row="3" Grid.Column="2" />

        <Button Text="*"
                Command="{Binding AddCharCommand}"
                CommandParameter="*"
                Grid.Row="4" Grid.Column="0" />

        <Button Text="0"
                Command="{Binding AddCharCommand}"
                CommandParameter="0"
                Grid.Row="4" Grid.Column="1" />

        <Button Text="#"
                Command="{Binding AddCharCommand}"
                CommandParameter="#"
                Grid.Row="4" Grid.Column="2" />
    </Grid>
</ContentPage>

Vlastnost Command prvního Button , který se zobrazí v této značce, je svázaná DeleteCharCommands AddCharCommand ; zbytek je svázán s znakem CommandParameter , který je stejný jako znak, který se zobrazí na tváři Button . Tady je program v akci:

Kalkulačka s využitím MVVM a příkazů

Vyvolání asynchronních metod

Příkazy mohou také vyvolat asynchronní metody. Toho dosáhnete pomocí async klíčových slov při await zadávání Execute metody:

DownloadCommand = new Command (async () => await DownloadAsync ());

To znamená, že DownloadAsync metoda je a Task měla by být očekávána:

async Task DownloadAsync ()
{
    await Task.Run (() => Download ());
}

void Download ()
{
    ...
}

Implementace navigační nabídky

Ukázkový program, který obsahuje veškerý zdrojový kód v této sérii článků, používá model ViewModel pro svou domovskou stránku. Tento Model ViewModel je definice krátké třídy se třemi vlastnostmi s názvem Type, Titlea Description které obsahují typ každé z ukázkových stránek, název a krátký popis. Kromě toho ViewModel definuje statickou vlastnost s názvem All kolekce všech stránek v programu:

public class PageDataViewModel
{
    public PageDataViewModel(Type type, string title, string description)
    {
        Type = type;
        Title = title;
        Description = description;
    }

    public Type Type { private set; get; }

    public string Title { private set; get; }

    public string Description { private set; get; }

    static PageDataViewModel()
    {
        All = new List<PageDataViewModel>
        {
            // Part 1. Getting Started with XAML
            new PageDataViewModel(typeof(HelloXamlPage), "Hello, XAML",
                                  "Display a Label with many properties set"),

            new PageDataViewModel(typeof(XamlPlusCodePage), "XAML + Code",
                                  "Interact with a Slider and Button"),

            // Part 2. Essential XAML Syntax
            new PageDataViewModel(typeof(GridDemoPage), "Grid Demo",
                                  "Explore XAML syntax with the Grid"),

            new PageDataViewModel(typeof(AbsoluteDemoPage), "Absolute Demo",
                                  "Explore XAML syntax with AbsoluteLayout"),

            // Part 3. XAML Markup Extensions
            new PageDataViewModel(typeof(SharedResourcesPage), "Shared Resources",
                                  "Using resource dictionaries to share resources"),

            new PageDataViewModel(typeof(StaticConstantsPage), "Static Constants",
                                  "Using the x:Static markup extensions"),

            new PageDataViewModel(typeof(RelativeLayoutPage), "Relative Layout",
                                  "Explore XAML markup extensions"),

            // Part 4. Data Binding Basics
            new PageDataViewModel(typeof(SliderBindingsPage), "Slider Bindings",
                                  "Bind properties of two views on the page"),

            new PageDataViewModel(typeof(SliderTransformsPage), "Slider Transforms",
                                  "Use Sliders with reverse bindings"),

            new PageDataViewModel(typeof(ListViewDemoPage), "ListView Demo",
                                  "Use a ListView with data bindings"),

            // Part 5. From Data Bindings to MVVM
            new PageDataViewModel(typeof(OneShotDateTimePage), "One-Shot DateTime",
                                  "Obtain the current DateTime and display it"),

            new PageDataViewModel(typeof(ClockPage), "Clock",
                                  "Dynamically display the current time"),

            new PageDataViewModel(typeof(HslColorScrollPage), "HSL Color Scroll",
                                  "Use a view model to select HSL colors"),

            new PageDataViewModel(typeof(KeypadPage), "Keypad",
                                  "Use a view model for numeric keypad logic")
        };
    }

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

Soubor XAML pro MainPage definuje, ListBox jehož ItemsSource vlastnost je nastavena na tuto All vlastnost a která obsahuje TextCell pro zobrazení Title a Description vlastnosti každé 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.MainPage"
             Padding="5, 0"
             Title="XAML Samples">

    <ListView ItemsSource="{x:Static local:PageDataViewModel.All}"
              ItemSelected="OnListViewItemSelected">
        <ListView.ItemTemplate>
            <DataTemplate>
                <TextCell Text="{Binding Title}"
                          Detail="{Binding Description}" />
            </DataTemplate>
        </ListView.ItemTemplate>
    </ListView>
</ContentPage>

Stránky se zobrazují v seznamu s možností posouvání:

Posuvný seznam stránek

Obslužná rutina v souboru kódu se aktivuje, když uživatel vybere položku. Obslužná rutina nastaví SelectedItem vlastnost ListBox zpět na null vybranou stránku a pak vytvoří instanci vybrané stránky a přejde na ni:

private async void OnListViewItemSelected(object sender, SelectedItemChangedEventArgs args)
{
    (sender as ListView).SelectedItem = null;

    if (args.SelectedItem != null)
    {
        PageDataViewModel pageData = args.SelectedItem as PageDataViewModel;
        Page page = (Page)Activator.CreateInstance(pageData.Type);
        await Navigation.PushAsync(page);
    }
}

Video

Xamarin Evolve 2016: MVVM byl vyroben jednoduchým a prismem Xamarin.Forms

Shrnutí

XAML je výkonný nástroj pro definování uživatelských rozhraní v Xamarin.Forms aplikacích, zejména při použití datových vazeb a MVVM. Výsledkem je čistá, elegantní a potenciálně použitelná reprezentace uživatelského rozhraní se všemi podporami pozadí v kódu.

Další videa o Xamarinu najdete na Channel 9 a YouTube.