Partager via


Partie 5. Des liaisons de données à MVVM

Le modèle architectural Model-View-ViewModel (MVVM) a été inventé en XAML à l’esprit. Le modèle applique une séparation entre trois couches logicielles : l’interface utilisateur XAML, appelée View ; les données sous-jacentes, appelées modèle ; et un intermédiaire entre la vue et le modèle, appelé ViewModel. La vue et le ViewModel sont souvent connectés via des liaisons de données définies dans le fichier XAML. BindingContext pour la vue est généralement une instance de ViewModel.

A Simple ViewModel

En guise d’introduction aux ViewModels, examinons d’abord un programme sans un. Précédemment, vous avez vu comment définir une nouvelle déclaration d’espace de noms XML pour permettre à un fichier XAML de référencer des classes dans d’autres assemblys. Voici un programme qui définit une déclaration d’espace de noms XML pour l’espace System de noms :

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

Le programme peut utiliser x:Static pour obtenir la date et l’heure actuelles de la propriété statique DateTime.Now et définir cette DateTime valeur sur un StackLayoutBindingContext :

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

BindingContext est une propriété spéciale : lorsque vous définissez l’élément BindingContext sur un élément, il est hérité par tous les enfants de cet élément. Cela signifie que tous les enfants de l’objet StackLayout ont ce même BindingContext, et qu’ils peuvent contenir des liaisons simples aux propriétés de cet objet.

Dans le programme DateTime one-Shot, deux des enfants contiennent des liaisons à des propriétés de cette DateTime valeur, mais deux autres enfants contiennent des liaisons qui semblent manquer un chemin de liaison. Cela signifie que la DateTime valeur elle-même est utilisée pour :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>

Le problème est que la date et l’heure sont définies une fois lorsque la page est créée pour la première fois et ne change jamais :

Afficher la date et l’heure d’affichage

Un fichier XAML peut afficher une horloge qui affiche toujours l’heure actuelle, mais il a besoin d’un code pour vous aider. Lorsque vous pensez en termes de MVVM, le Modèle et ViewModel sont des classes écrites entièrement dans le code. La vue est souvent un fichier XAML qui fait référence aux propriétés définies dans ViewModel par le biais de liaisons de données.

Un modèle approprié est ignorant du ViewModel, et un ViewModel approprié est ignorant de la vue. Toutefois, souvent, un programmeur adapte les types de données exposés par ViewModel aux types de données associés à des interfaces utilisateur particulières. Par exemple, si un modèle accède à une base de données qui contient des chaînes ASCII de caractères 8 bits, ViewModel doit effectuer une conversion entre ces chaînes en chaînes Unicode pour prendre en charge l’utilisation exclusive d’Unicode dans l’interface utilisateur.

Dans des exemples simples de MVVM (comme ceux présentés ici), il n’existe souvent aucun modèle, et le modèle implique simplement une vue et viewModel liée avec des liaisons de données.

Voici un ViewModel pour une horloge avec une seule propriété nommée DateTime, qui met à jour cette DateTime propriété toutes les secondes :

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 implémente généralement l’interface INotifyPropertyChanged , ce qui signifie que la classe déclenche un PropertyChanged événement chaque fois qu’une de ses propriétés change. Le mécanisme de liaison de données dans Xamarin.Forms attache un gestionnaire à cet PropertyChanged événement afin qu’il puisse être averti lorsqu’une propriété change et conserve la cible mise à jour avec la nouvelle valeur.

Une horloge basée sur ce ViewModel peut être aussi simple que celle-ci :

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

Notez comment le ClockViewModel paramètre est défini sur les LabelBindingContext balises d’élément de propriété using. Vous pouvez également instancier le ClockViewModel fichier dans une Resources collection et le BindingContext définir via une StaticResource extension de balisage. Ou, le fichier code-behind peut instancier le ViewModel.

Extension Binding de balisage sur la Text propriété des Label formats de la DateTime propriété. Voici l’affichage :

Affichage de la date et de l’heure via ViewModel

Il est également possible d’accéder aux propriétés individuelles de la DateTime propriété de ViewModel en séparant les propriétés par des points :

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

Interactive MVVM

La machine virtuelle virtuelle est souvent utilisée avec des liaisons de données bidirectionnelle pour une vue interactive basée sur un modèle de données sous-jacent.

Voici une classe nommée HslViewModel qui convertit une Color valeur en Huevaleurs, Saturationet Luminosity inversement :

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

Les modifications apportées aux Huepropriétés et Luminosity aux propriétés Saturationentraînent la modification de la Color propriété et les modifications qui Color entraînent la modification des trois autres propriétés. Cela peut sembler une boucle infinie, sauf que la classe n’appelle pas l’événement PropertyChanged , sauf si la propriété a changé. Cela met fin à la boucle de commentaires incontrôlable autrement incontrôlable.

Le fichier XAML suivant contient une BoxView propriété dont Color la propriété est liée à la Color propriété de ViewModel, et trois Slider et trois Label vues liées à la Huepropriété , Saturationet Luminosity aux propriétés :

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

La liaison sur chacun Label est la valeur par défaut OneWay. Il doit uniquement afficher la valeur. Mais la liaison sur chacun d’eux Slider est TwoWay. Cela permet l’initialisation Slider à partir de ViewModel. Notez que la Color propriété est définie Aqua lorsque ViewModel est instancié. Toutefois, une modification de la Slider valeur doit également définir une nouvelle valeur pour la propriété dans ViewModel, qui calcule ensuite une nouvelle couleur.

MVVM utilisant des liaisons de données bidirectionnelle

Commandes avec ViewModels

Dans de nombreux cas, le modèle MVVM est limité à la manipulation d’éléments de données : les objets d’interface utilisateur dans les objets de données parallèles view dans ViewModel.

Toutefois, parfois, la vue doit contenir des boutons qui déclenchent diverses actions dans ViewModel. Mais ViewModel ne doit pas contenir Clicked de gestionnaires pour les boutons, car cela lierait ViewModel à un paradigme d’interface utilisateur particulier.

Pour permettre aux ViewModels d’être plus indépendants des objets d’interface utilisateur particuliers, mais toujours autoriser les méthodes à appeler dans ViewModel, une interface de commande existe. Cette interface de commande est prise en charge par les éléments suivants dans Xamarin.Forms:

  • Button
  • MenuItem
  • ToolbarItem
  • SearchBar
  • TextCell (et donc aussi ImageCell)
  • ListView
  • TapGestureRecognizer

À l’exception de l’élément et ListView de l’élémentSearchBar, ces éléments définissent deux propriétés :

  • Command de type System.Windows.Input.ICommand
  • CommandParameter de type Object

Définit SearchBar et SearchCommandParameter propriétés, tandis que la ListView propriété définit une RefreshCommand propriété de type ICommand.SearchCommand

L’interface ICommand définit deux méthodes et un événement :

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

ViewModel peut définir des propriétés de type ICommand. Vous pouvez ensuite lier ces propriétés à la Command propriété de chacun Button ou d’un autre élément, ou peut-être une vue personnalisée qui implémente cette interface. Vous pouvez éventuellement définir la CommandParameter propriété pour identifier des objets individuels Button (ou d’autres éléments) liés à cette propriété ViewModel. En interne, les Button appels de la Execute méthode chaque fois que l’utilisateur appuie sur , Buttonpassant à la Execute méthode son CommandParameter.

La méthode et CanExecuteChanged l’événement CanExecute sont utilisés pour les cas où un Button appui peut être actuellement non valide, auquel cas il Button doit se désactiver. Appels ButtonCanExecute lorsque la propriété est définie pour la Command première fois et chaque fois que l’événement CanExecuteChanged est déclenché. Si CanExecute elle est retournée false, le Button désactive lui-même et ne génère Execute pas d’appels.

Pour obtenir de l’aide sur l’ajout de commandes à vos ViewModels, Xamarin.Forms définit deux classes qui implémentent ICommand: Command et Command<T>T est le type des arguments vers Execute et CanExecute. Ces deux classes définissent plusieurs constructeurs plus une ChangeCanExecute méthode que ViewModel peut appeler pour forcer l’objet Command à déclencher l’événement CanExecuteChanged .

Voici un ViewModel pour un pavé numérique simple destiné à entrer des numéros de téléphone. Notez que la méthode et CanExecute la Execute méthode sont définies en tant que fonctions lambda directement dans le constructeur :

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

Ce ViewModel part du principe que la AddCharCommand propriété est liée à la Command propriété de plusieurs boutons (ou tout autre élément qui a une interface de commande), chacun d’entre eux est identifié par le CommandParameter. Ces boutons ajoutent des caractères à une InputString propriété, qui est ensuite mise en forme comme numéro de téléphone pour la DisplayText propriété.

Il existe également une deuxième propriété de type ICommand nommée DeleteCharCommand. Cela est lié à un bouton d’espacement arrière, mais le bouton doit être désactivé s’il n’y a pas de caractères à supprimer.

Le pavé numérique suivant n’est pas aussi sophistiqué visuellement qu’il pourrait l’être. Au lieu de cela, le balisage a été réduit à un minimum pour illustrer plus clairement l’utilisation de l’interface de commande :

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

La Command propriété de la première Button qui apparaît dans ce balisage est liée au DeleteCharCommand; le reste est lié au reste avec AddCharCommand un CommandParameter caractère identique au caractère qui apparaît sur le Button visage. Voici le programme en action :

Calculatrice utilisant MVVM et commandes

Appel de méthodes asynchrones

Les commandes peuvent également appeler des méthodes asynchrones. Pour ce faire, utilisez les mot clé et await les async mot clé lors de la spécification de la Execute méthode :

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

Cela indique que la DownloadAsync méthode est une Task méthode et doit être attendue :

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

void Download ()
{
    ...
}

Implémentation d’un menu de navigation

L’exemple de programme qui contient tout le code source de cette série d’articles utilise un ViewModel pour sa page d’accueil. Ce ViewModel est une définition d’une classe courte avec trois propriétés nommées Type, Titleet Description qui contiennent le type de chacun des exemples de pages, un titre et une brève description. En outre, ViewModel définit une propriété statique nommée All qui est une collection de toutes les pages du programme :

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

Le fichier XAML pour MainPage définir une ListBox propriété dont ItemsSource la propriété est définie sur cette All propriété et qui contient un TextCell pour afficher les propriétés et Description les Title propriétés de chaque page :

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

Les pages sont affichées dans une liste à défilement :

Liste modifiable des pages

Le gestionnaire du fichier code-behind est déclenché lorsque l’utilisateur sélectionne un élément. Le gestionnaire définit la SelectedItem propriété du ListBox retour null , puis instancie la page sélectionnée et y accède :

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

Vidéo

Xamarin Evolve 2016 : MVVM Simple avec Xamarin.Forms et Prism

Résumé

XAML est un outil puissant pour définir des interfaces utilisateur dans Xamarin.Forms les applications, en particulier lorsque la liaison de données et la machine virtuelle virtuelle sont utilisées. Le résultat est une représentation propre, élégante et potentiellement outilable d’une interface utilisateur avec toute la prise en charge en arrière-plan dans le code.

Retrouvez d’autres vidéos Xamarin sur Channel 9 et YouTube.