nRoute – Les bases de nRoute et le MVVM

4 minutes read

Avant de commencer

Si vous n’avez jamais entendu parlé de nRoute je vous invite à lire mon précédent article.

Téléchargement de nRoute

Si ce n’est pas déjà fait je vous invite à télécharger nRoute framework (version 0.4.5 au moment où sont écrites ces lignes).

Vous pouvez télécharger nRoute framework ici : http://nroute.codeplex.com/releases/view/44449

Création du projet et ajout des références

Dans cet article je présenterai les approches pour les trois plateformes que cible nRoute. Aussi je vous invite à créer un projet dans la technologie de votre choix parmi Silverlight, WPF et WP7.

Ensuite nous pouvons ajouter une référence à nRoute et à System.Windows.Interactivity (pour les behaviors, les triggers, etc…).

nRoute est livré compilé en trois exemplaire pour chacune des plateformes qu’il cible.

nRouteReference

Le screenshot ci-dessus montre le résultat que l’on a une fois les références ajoutées à un projet Silverlight.

Mise en route

Afin de pouvoir profiter de nRoute il faut tout d’abord l’initialiser. Pour ce faire nous allons modifier le fichier App.xaml.

La mise en route diffère selon que notre projet est en Silverlight, WPF ou WP7. Aussi voici comment faire pour chaque plateforme.

Le namespace utilisé pour nRoute est le suivant :

xmlns:n="http://nRoute/schemas/2010/xaml"

Il sera utilisé dans les exemples sauf pour les exemples ciblant WP7 car ce namespace n’est pas disponible sur cette plateforme.

Silverlight

Ajout du service d’application nRoute dans la propriété ServiceLifeTimeObjects de notre application.

<Application xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:n="http://nRoute/schemas/2010/xaml"
             x:Class="nRoute_MVVM_Basics.App">
    <Application.ApplicationLifetimeObjects>
        <n:nRouteApplicationService />
    </Application.ApplicationLifetimeObjects>
</Application>

Windows Phone 7

Pareil qu’en Silverlight à la différence qu’on ne peut pas utiliser pas le namespace générique.

<Application
    x:Class="nRoute_MVVM_Basics_Phone.App"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:shell="clr-namespace:Microsoft.Phone.Shell;assembly=Microsoft.Phone"
    xmlns:n="clr-namespace:nRoute.ApplicationServices;assembly=nRoute.Framework">

    <Application.ApplicationLifetimeObjects>
        <n:nRouteApplicationService />

        <shell:PhoneApplicationService
            Launching="Application_Launching" Closing="Application_Closing"
            Activated="Application_Activated" Deactivated="Application_Deactivated"/>
    </Application.ApplicationLifetimeObjects>
</Application>

WPF

La propriété ApplicationLifetimeObjects n’existant pas en WPF une manipulation supplémentaire est nécessaire. Notre application doit désormais hériter de nRoute.ApplicationServices.Application.

Tout d’abord le XAML

<n:Application x:Class="nRoute_MVVM_Basics_WPF.App"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:n="http://nRoute/schemas/2010/xaml"
             StartupUri="MainWindow.xaml">
    <n:Application.ApplicationLifetimeObjects>
        <n:nRouteApplicationService />
    </n:Application.ApplicationLifetimeObjects>
</n:Application>

Ensuite le code behind :

namespace nRoute_MVVM_Basics_WPF
{
    public partial class App : nRoute.ApplicationServices.Application
    {
    }
}

Création de la vue

La vue que nous utiliserons ici est simplissime et sera la même sur les trois plateforme.

<Grid x:Name="LayoutRoot">
    <TextBlock Text="{Binding Date}" />
</Grid>

Création du ViewModel

nRoute fournit une classe de base pour les ViewModel qui implémente l’interface INotifyPropertyChanged et fourni une méthode NotifyPropertyChanged prenant en paramètre une lambda à la place d’une chaîne de caractère.

J’apprécie cette approche car elle évite bien des erreurs lors du renommage des propriétés d’un ViewModel.

Elle a cependant un coût non négligeable en performance.

Je vous invite à lire cet article en anglais si vous êtes interessés par les problématiques de performances avec les différentes implémentations de INotifyPropertyChanged http://www.pochet.net/blog/2010/06/25/inotifypropertychanged-implementations-an-overview/.

L’utilisation de cette classe de base est complètement optionnelle au fonctionnement de nRoute vous pouvez donc choisir l’implémentation de INotifyPropertyChanged qui correspond le plus à vos besoins ou à vos goûts.

Voici l’implémentation de notre ViewModel (notez l’implémentation fortement typée de NotifyPropertyChanged).

public class MainWindowViewModel : ViewModelBase
{
    private DateTime? _date;

    public DateTime? Date
    {
        get
        {
            return _date;
        }

        set
        {
            if (_date != value)
            {
                _date = value;
                NotifyPropertyChanged(() => Date);
            }
        }
    }

    public MainWindowViewModel()
    {
        Date = DateTime.UtcNow;
    }
}

Association du ViewModel et de la vue

Maintenant que nous avons une vue et un ViewModel il faut les associer. L’association d’un ViewModel et d’une vue se fait grâce à des attributs (comme beaucoup de choses dans nRoute).

Ici, il existe deux façons de procéder :

Association depuis le ViewModel grâce à l’attribut MapViewModel

[MapViewModel(typeof(MyView))]
public class MyViewViewModel : ViewModelBase

Association depuis le code-behind de la vue grâce à l’attribut MapView

[MapView(typeof(MyViewViewModel))]
public partial class MyView

Vous pouvez choisir l’une ou l’autre méthode à votre convenance. J’ai, pour ma part, tendance à utiliser l’attribut MapViewModel dans la plupart des cas.

Ces attributs permettent à nRoute de construire des relations entre nos vues et viewmodels cependant ils n’induisent pas l’injection automatique du ViewModel dans le datacontext de la Vue. Cette injection est réalisée grâce à un behavior.

Nous allons donc ajouter les namespaces de nRoute et de System.Windows.Interactivity dans notre vue et ajouter le behavior.

En Silverlight

<UserControl x:Class="nRoute_MVVM_Basics.MainPage"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:i="clr-namespace:System.Windows.Interactivity;assembly=System.Windows.Interactivity"
    xmlns:n="http://nRoute/schemas/2010/xaml">

    <i:Interaction.Behaviors>
        <n:BridgeViewModelBehavior />
    </i:Interaction.Behaviors>

    <Grid x:Name="LayoutRoot">
        <TextBlock Text="{Binding Date}" />
    </Grid>
</UserControl>

En WP7

<phone:PhoneApplicationPage
    x:Class="nRoute_MVVM_Basics_Phone.MainPage"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:phone="clr-namespace:Microsoft.Phone.Controls;assembly=Microsoft.Phone"
    xmlns:shell="clr-namespace:Microsoft.Phone.Shell;assembly=Microsoft.Phone"
    xmlns:i="clr-namespace:System.Windows.Interactivity;assembly=System.Windows.Interactivity"
    xmlns:nBehaviors="clr-namespace:nRoute.Behaviors;assembly=nRoute.Framework"
    FontFamily="{StaticResource PhoneFontFamilyNormal}"
    FontSize="{StaticResource PhoneFontSizeNormal}"
    Foreground="{StaticResource PhoneForegroundBrush}"
    SupportedOrientations="Portrait"
    Orientation="Portrait"
    shell:SystemTray.IsVisible="True">

    <i:Interaction.Behaviors>
        <nBehaviors:BridgeViewModelBehavior />
    </i:Interaction.Behaviors>

    <Grid x:Name="LayoutRoot" Background="Transparent">
        <TextBlock Text="{Binding Date}" />
    </Grid>

</phone:PhoneApplicationPage>

En WPF

<Window x:Class="nRoute_MVVM_Basics_WPF.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:i="clr-namespace:System.Windows.Interactivity;assembly=System.Windows.Interactivity"
        xmlns:n="http://nRoute/schemas/2010/xaml"
        Title="MainWindow" Height="350" Width="525">
    <i:Interaction.Behaviors>
        <n:BridgeViewModelBehavior />
    </i:Interaction.Behaviors>

    <Grid x:Name="LayoutRoot" Background="White">
        <TextBlock Text="{Binding Date}" />
    </Grid>
</Window>

Un peu de détail

Une fois nRoute initialisé, nRoute va enrichir le comportement de Silverlight, WPF ou WP7 en particulier grâce au Resource Locator Framework, alias RLF. Lorsque BridgeViewModelBehavior est attaché à un objet graphique, il fait appel au RLF afin de rechercher un ViewModel correspondant à l’objet courant grâce aux attributs MapViewModel et/ou MapView.

La glue est donc ici. C’est ce Behavior couplé au RLF qui permettent d’externaliser la création du ViewModel.

Conclusion

Vous savez maintenant initialiser nRoute pour les différentes plateformes, affecter un ViewModel à une vue et l’initialiser grâce au BridgeViewModelBehavior.

Vous avez de plus vu la classe ViewModelBase avec ses avantages et ses inconvénients.

Dans le prochain article je vous montrerai comment faire des commandes et des commandes inversées avec nRoute.

Comme d’habitude vous trouverez la solution associée à cet article sur mon skydrive.

Updated:

Leave a Comment