Partie 5. Des liaisons de données à MVVM

Télécharger l’exemple Télécharger l’exemple

Le modèle architectural MVVM (Model-ViewModel) a été inventé avec XAML à l’esprit. Le modèle applique une séparation entre trois couches logicielles : l’interface utilisateur XAML, appelée Vue ; 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. Le BindingContext pour la vue est généralement un instance du ViewModel.

Un mode d’affichage simple

En guise d’introduction à ViewModels, examinons d’abord un programme sans programme. Vous avez vu plus tôt 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 de System 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 sur BindingContext un StackLayout:

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

BindingContext est une propriété spéciale : lorsque vous définissez sur BindingContext un élément, il est hérité par tous les enfants de cet élément. Cela signifie que tous les enfants de ont StackLayout 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 aux propriétés de cette DateTime valeur, mais deux autres enfants contiennent des liaisons qui semblent manquer d’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 générée pour la première fois, et ne changent jamais :

de l’heure Affichage de la date et de l’heure

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, model et ViewModel sont des classes entièrement écrites en code. La vue est souvent un fichier XAML qui fait référence aux propriétés définies dans ViewModel via des liaisons de données.

Un modèle approprié ignore le ViewModel, et un ViewModel approprié ignore la vue. Toutefois, un programmeur adapte souvent 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, le ViewModel doit convertir 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 (tels que ceux présentés ici), il n’existe souvent aucun modèle, et le modèle implique simplement une vue et un viewModel liés à 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émentent généralement l’interface INotifyPropertyChanged , ce qui signifie que la classe déclenche un événement chaque fois qu’une PropertyChanged 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 maintenir la cible à jour avec la nouvelle valeur.

Une horloge basée sur ce ViewModel peut être aussi simple que ceci :

<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 est ClockViewModel défini sur le BindingContext des balises d’élément Label de propriété using. Vous pouvez également instancier le ClockViewModel dans une Resources collection et le définir sur via une StaticResource extension de BindingContext balisage. Ou bien, le fichier code-behind peut instancier le ViewModel.

L’extension Binding de balisage sur la Text propriété du Label met en forme 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é du ViewModel en séparant les propriétés par des points :

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

Interactive MVVM

MVVM est souvent utilisé 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 et vice versa :

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 , Saturationet Luminosity entraînent la modification de la Color propriété, et les modifications apportées à Color entraînent la modification des trois autres propriétés. Cela peut ressembler à 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 autrement incontrôlable.

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

<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 chaque Label est la valeur par défaut OneWay. Il suffit d’afficher la valeur. Mais la liaison sur chacun d’eux Slider est TwoWay. Cela permet d’initialiser le Slider à partir du ViewModel. Notez que la Color propriété est définie sur Aqua lorsque le ViewModel est instancié. Toutefois, une modification du Slider doit également définir une nouvelle valeur pour la propriété dans le ViewModel, qui calcule ensuite une nouvelle couleur.

MVVM à l’aide de liaisons de données Two-Way

Commande avec ViewModels

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

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

Pour permettre aux ViewModels d’être plus indépendants des objets d’interface utilisateur particuliers, mais tout en autorisant l’appel de méthodes dans le 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 SearchBar et ListView , ces éléments définissent deux propriétés :

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

Définit SearchBarSearchCommand les propriétés et SearchCommandParameter , tandis que définit ListView une RefreshCommand propriété de type ICommand.

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) qui sont liés à cette propriété ViewModel. En interne, le Button appelle la Execute méthode chaque fois que l’utilisateur appuie sur , Buttonen passant à la Execute méthode son CommandParameter.

La CanExecute méthode et CanExecuteChanged l’événement sont utilisés pour les cas où un Button appui peut être actuellement non valide, auquel cas le Button doit se désactiver lui-même. 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 retourne false, le Button se désactive lui-même et ne génère pas d’appels Execute .

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 dans Execute et CanExecute. Ces deux classes définissent plusieurs constructeurs plus une ChangeCanExecute méthode que le ViewModel peut appeler pour forcer l’objet Command à déclencher l’événement CanExecuteChanged .

Voici un ViewModel pour un clavier simple destiné à entrer des numéros de téléphone. Notez que la Execute méthode et CanExecute est définie en tant que fonctions lambda à droite 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 suppose 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 étant identifié par .CommandParameter Ces boutons ajoutent des caractères à une InputString propriété, qui est ensuite mise en forme en tant que 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. Il 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 clavier suivant n’est pas aussi sophistiqué visuellement qu’il pourrait l’être. Au lieu de cela, le balisage a été réduit au 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é du premier Button qui apparaît dans ce balisage est liée à ; DeleteCharCommandles autres sont liés au AddCharCommand avec un CommandParameter qui est le même que le caractère qui apparaît sur le Button visage. Voici le programme en action :

à l’aide de MVVM et de commandes

Appel de méthodes asynchrones

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

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

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

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

void Download ()
{
    ...
}

Implémentation d’un menu de navigation

Le programme XamlSamples 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 chacune 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éfinit un ListBox dont ItemsSource la propriété est définie sur cette All propriété et qui contient un TextCell pour afficher les Title propriétés et Description 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 déroulante des pages

Le gestionnaire dans le fichier code-behind est déclenché lorsque l’utilisateur sélectionne un élément. Le gestionnaire définit la SelectedItem propriété du ListBox back sur 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 fait simple avec Xamarin.Forms et Prism

Résumé

XAML est un outil puissant pour définir des interfaces utilisateur dans les applications, en Xamarin.Forms particulier lorsque la liaison de données et la machine virtuelle MVVM 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 d’arrière-plan dans le code.

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