{"id":775,"date":"2014-11-14T01:58:49","date_gmt":"2014-11-13T23:58:49","guid":{"rendered":"http:\/\/dev.bratched.fr\/fr\/?p=775"},"modified":"2014-11-14T01:58:49","modified_gmt":"2014-11-13T23:58:49","slug":"mvvmlight-5-0-et-la-navigation","status":"publish","type":"post","link":"https:\/\/bratched.com\/fr\/2014\/11\/14\/mvvmlight-5-0-et-la-navigation\/","title":{"rendered":"MvvmLight 5.0 et la navigation"},"content":{"rendered":"<h1>Nouveaut\u00e9s<\/h1>\n<p>Une grande nouveaut\u00e9 de <a href=\"https:\/\/mvvmlight.codeplex.com\/\">MVVMLight5 <\/a>est l&rsquo;apparition du\u00a0<strong>INavigationService<\/strong>.<\/p>\n<p><a href=\"http:\/\/dev.bratched.fr\/fr\/wp-content\/uploads\/sites\/2\/2014\/11\/NavigationPageMVVMLight2-e1419726277311.png\"><img decoding=\"async\" loading=\"lazy\" class=\"alignnone wp-image-776\" src=\"http:\/\/dev.bratched.fr\/fr\/wp-content\/uploads\/sites\/2\/2014\/11\/NavigationPageMVVMLight2-e1419726277311.png\" alt=\"\" width=\"480\" height=\"333\" srcset=\"https:\/\/bratched.com\/fr\/wp-content\/uploads\/sites\/2\/2014\/11\/NavigationPageMVVMLight2-e1419726277311.png 763w, https:\/\/bratched.com\/fr\/wp-content\/uploads\/sites\/2\/2014\/11\/NavigationPageMVVMLight2-e1419726277311-300x208.png 300w\" sizes=\"(max-width: 480px) 100vw, 480px\" \/><\/a><\/p>\n<p>Le <strong>INavigationService<\/strong> est un Pattern permettant la navigation dans l&rsquo;application sans utiliser la couche visuelle. Il est alors possible de migrer le m\u00eame code\u00a0sous diff\u00e9rentes plateformes sans les particularit\u00e9s de la navigation.<\/p>\n<p>Il sera \u00e9galement possible de tester les actions de navigation gr\u00e2ce aux tests unitaires automatis\u00e9s.<\/p>\n<p><!--more--><\/p>\n<h1>Navigation entre les pages<\/h1>\n<p>Un petit rappel des diff\u00e9rentes impl\u00e9mentations de la navigation entre les pages d&rsquo;une application.<\/p>\n<h2>Sans MVVM et sans INavigationService<\/h2>\n<p>Dans une application standard (non MVVM), le passage d&rsquo;une page \u00e0 l&rsquo;autre va se faire de la fa\u00e7on suivante. Sur le click du bouton, on appelle la page concern\u00e9e.<\/p>\n<p>En Xaml :<\/p>\n<pre class=\"lang:default decode:true \">&lt;Button Content=\"Go to Page 2\" \n                VerticalAlignment=\"Center\"\n                HorizontalAlignment=\"Center\"\n                Click=\"Button_Click\"\/&gt;<\/pre>\n<p>En Code Behind (Ici dans une application Windows 8.x \/ Windows Phone 8 Xaml)<\/p>\n<pre class=\"lang:default decode:true\">private void Button_Click(object sender, RoutedEventArgs e)\n{\n    Frame.Navigate(typeof(Page2));\n}\n<\/pre>\n<p>&nbsp;<\/p>\n<h2>En MVVM sans impl\u00e9mentation de l&rsquo;\u00e9v\u00e8nement \u00ab\u00a0Click\u00a0\u00bb<\/h2>\n<p>Afin de ne pas coder les actions dans l&rsquo;interface visuelle, nous allons passer par des <strong>ICommand<\/strong>.<\/p>\n<p>MVVM Light poss\u00e8de d\u00e9j\u00e0 les m\u00e9canismes pour utiliser les actions avec des <strong>RelayCommand<\/strong>.<\/p>\n<p>Nous utilisons une classe <strong>MainViewModel<\/strong> o\u00f9 nous allons coder l&rsquo;action.<\/p>\n<pre class=\"lang:default decode:true \">public class MainViewModel\n{\n    public ICommand NavigatePage2Command { get; private set; }\n    public MainViewModel()\n    {\n        NavigatePage2Command = new RelayCommand(()=&gt;\n        {\n\t\/\/ Code to Execute\n        });\n    }\n}\n<\/pre>\n<p>Cette classe est ensuite associ\u00e9e dans le XAML au niveau de la d\u00e9finition de la Page.<\/p>\n<pre class=\"lang:default decode:true\">DataContext=\"{Binding Source={StaticResource Locator}, Path=MainViewModel}\"<\/pre>\n<p>Le Bouton est alors cod\u00e9 de cette fa\u00e7on. L&rsquo;action \u00ab\u00a0<strong>Command<\/strong>\u00a0\u00bb remplace l&rsquo;\u00e9v\u00e8nement \u00ab\u00a0<strong>Click<\/strong>\u00a0\u00bb : Le bouton utilise le <strong>Binding<\/strong> pour associer l&rsquo;\u00e9v\u00e8nement \u00e0 l&rsquo;action.<\/p>\n<pre class=\"lang:default decode:true\">&lt;Button \n  VerticalAlignment=\"Center\" \n  HorizontalAlignment=\"Center\"\n  Content=\"Page 2\"\n  Command=\"{Binding NavigatePage2Command}\"\n\/&gt;<\/pre>\n<h1>Les probl\u00e8mes de la navigation.<\/h1>\n<h2>Premier probl\u00e8me : L&rsquo;ind\u00e9pendance de la Vue<\/h2>\n<p>La command se trouve dans le ViewModel. L&rsquo;objet <strong>Frame<\/strong> qui est un objet visuel n&rsquo;est pas accessible sauf \u00e0 ajouter un espace de nommage li\u00e9 \u00e0 la vue pour pouvoir le manipuler. En faisant cela on \u00ab\u00a0casse\u00a0\u00bb le\u00a0pattern <strong>ViewModel<\/strong>.<\/p>\n<h2>Deuxi\u00e8me probl\u00e8me : Le codage sp\u00e9cifique<\/h2>\n<p>L&rsquo;objet Frame est sp\u00e9cifique aux applications Windows 8 et Universal Apps. Si vous souhaitez porter ce code en WPF ou Windows Phone 8.0 , 8.1 version Silverlight ou Xamarin Android \/ iPhone, la syntaxe sera diff\u00e9rente.<\/p>\n<p>Ce qui se fait de plus courant, est l&rsquo;impl\u00e9mentation d&rsquo;une <strong>interface<\/strong> souvent appel\u00e9e INavigationService et de sa classe associ\u00e9e NavigationService.<\/p>\n<p>INavigationService va contenir les \u00e9l\u00e9ments de navigation, souvent des m\u00e9thodes NavigateToPage1, GoBack(),&#8230; et son impl\u00e9mentation (NavigationService) va coder les m\u00e9thodes de navigation propre \u00e0 chaque plateforme.<\/p>\n<p>Depuis quelques semaines, MVVM Light 5, fournit tout ce m\u00e9canisme \u00ab\u00a0in the Box\u00a0\u00bb.<\/p>\n<h1>INavigationService du MVVM Light 5.0<\/h1>\n<h2>Etape 1 : D\u00e9finition du Service dans ViewModelLocator.<\/h2>\n<p>Le ViewModelLocator sert \u00e0 initialiser tous les services et enregistrer\u00a0tous les ViewModel consult\u00e9s dans les vues.<\/p>\n<p>On va ajouter la ligne suivante dans son constructeur :<\/p>\n<pre class=\"lang:default decode:true\">SimpleIoc.Default.Register&lt;INavigationService&gt;(() =&gt; CreateNavigationService());<\/pre>\n<p>ce qui donne :<\/p>\n<pre class=\"lang:default decode:true\">static ViewModelLocator()\n{\n    ServiceLocator.SetLocatorProvider(() =&gt; SimpleIoc.Default);\n    SimpleIoc.Default.Register&lt;INavigationService&gt;(() =&gt; CreateNavigationService());\n...            \n    SimpleIoc.Default.Register&lt;MainViewModel&gt;();\n    SimpleIoc.Default.Register&lt;Page2ViewModel&gt;();\n}\n<\/pre>\n<p><strong>CreateNavigationService()<\/strong> va contenir un r\u00e9f\u00e9rentiel sous forme de configuration de chaque page :<\/p>\n<pre class=\"lang:default decode:true\">private static INavigationService CreateNavigationService()\n{\n    var navigationService = new NavigationService();\n    navigationService.Configure(\"Page2\", typeof(Page2));\n    return navigationService;\n}<\/pre>\n<p>&nbsp;<\/p>\n<p>Si vous avez plusieurs pages sur lesquelles vous voulez naviguer il faudra les d\u00e9finir \u00e0 cet endroit avec la m\u00e9thode <strong>Configure<\/strong>.<\/p>\n<p>Le r\u00e9f\u00e9rencement de ces pages s&rsquo;effectue par une \u00ab\u00a0string\u00a0\u00bb ce qui peut \u00eatre source d&rsquo;erreur. Je vous recommande de passer par la d\u00e9finition de constantes pour b\u00e9n\u00e9ficier de l&rsquo;IntelliSense et \u00e9galement \u00e9viter toute confusion.<\/p>\n<pre class=\"lang:default decode:true \">public const string NavigationPage2 = \"Page2\";<\/pre>\n<h2>Etape 2 : Navigation vers une page<\/h2>\n<p>Nous allons voir maintenant comment appeler une page dans le <strong>ViewModel<\/strong>.<\/p>\n<p>Sur le <strong>RelayCommand<\/strong> (associ\u00e9 au bouton dans le XAML), l&rsquo;appel va se faire de la fa\u00e7on suivante :<\/p>\n<pre class=\"lang:default decode:true \">NavigatePage2Command = new RelayCommand(()=&gt;\n    {\n        INavigationService navigationService = SimpleIoc.Default.GetInstance&lt;INavigationService&gt;();\n        navigationService.NavigateTo(ViewModelLocator.NavigationPage2);\n    });<\/pre>\n<h2>Etape 3 (Optionnelle) : Retour vers la page pr\u00e9c\u00e9dente<\/h2>\n<p>On associe une action sur le <strong>Command<\/strong>\u00a0(NavigateBackCommand dans cet exemple). L&rsquo;action est\u00a0associ\u00e9e au bouton retour, dans cette action,\u00a0on utilise la m\u00e9thode <strong>GoBack()<\/strong>. Cette\u00a0instruction provient directement de MVVMLight 5, il n&rsquo;y a rien de plus \u00e0 faire.<\/p>\n<pre class=\"lang:default decode:true \">public ICommand NavigateBackCommand { get; private set; }\n\npublic Page2ViewModel()\n{\n    NavigateBackCommand = new RelayCommand(() =&gt;\n    {\n        INavigationService navigationService = SimpleIoc.Default.GetInstance&lt;INavigationService&gt;();\n        navigationService.GoBack();\n    });\n}<\/pre>\n<h1>Conclusion<\/h1>\n<p><strong>MVVMLight<\/strong> dans sa version 5.0 simplifie de nouveau un peu plus le pattern M-V-VM en proposant les impl\u00e9mentations de navigation courantes directement dans ce Framework.<\/p>\n<p>Avec une version \u00ab\u00a0Portable\u00a0\u00bb, il est possible de cr\u00e9er un code tr\u00e8s propre et ind\u00e9pendant d&rsquo;une plateforme tr\u00e8s facilement.<\/p>\n<p>Le code est ici<\/p>\n<p><a title=\"Code Source de la navigation MVVMLight 5\" href=\"http:\/\/1drv.ms\/1xXt8t4\" target=\"_blank\" rel=\"noopener noreferrer\"><img decoding=\"async\" loading=\"lazy\" class=\"alignnone size-full wp-image-633\" src=\"http:\/\/dev.bratched.fr\/fr\/wp-content\/uploads\/sites\/2\/2014\/05\/download-10-icon-256.png\" alt=\"T\u00e9l\u00e9chargement du Code\" width=\"256\" height=\"256\" srcset=\"https:\/\/bratched.com\/fr\/wp-content\/uploads\/sites\/2\/2014\/05\/download-10-icon-256.png 256w, https:\/\/bratched.com\/fr\/wp-content\/uploads\/sites\/2\/2014\/05\/download-10-icon-256-150x150.png 150w\" sizes=\"(max-width: 256px) 100vw, 256px\" \/><\/a><\/p>\n","protected":false},"excerpt":{"rendered":"<p>Nouveaut\u00e9s Une grande nouveaut\u00e9 de MVVMLight5 est l&rsquo;apparition du\u00a0INavigationService. Le INavigationService est un Pattern permettant la navigation dans l&rsquo;application sans utiliser la couche visuelle. Il est alors possible de migrer le m\u00eame code\u00a0sous diff\u00e9rentes plateformes sans les particularit\u00e9s de la navigation. Il sera \u00e9galement possible de tester les actions de navigation gr\u00e2ce aux tests unitaires [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[59,62,63],"tags":[124,125,126,127,4,128,129,130,131],"aioseo_notices":[],"_links":{"self":[{"href":"https:\/\/bratched.com\/fr\/wp-json\/wp\/v2\/posts\/775"}],"collection":[{"href":"https:\/\/bratched.com\/fr\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/bratched.com\/fr\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/bratched.com\/fr\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/bratched.com\/fr\/wp-json\/wp\/v2\/comments?post=775"}],"version-history":[{"count":0,"href":"https:\/\/bratched.com\/fr\/wp-json\/wp\/v2\/posts\/775\/revisions"}],"wp:attachment":[{"href":"https:\/\/bratched.com\/fr\/wp-json\/wp\/v2\/media?parent=775"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/bratched.com\/fr\/wp-json\/wp\/v2\/categories?post=775"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/bratched.com\/fr\/wp-json\/wp\/v2\/tags?post=775"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}