MVVM - Connexion de ViewModel

Dans ce chapitre, nous verrons comment connecter ViewModel. C'est une continuation du dernier chapitre dans lequel nous avons discuté de la première construction de View. Maintenant, la forme suivante de la première construction est unmeta-pattern qui est connu comme ViewModelLocator. Il s'agit d'un pseudo motif et se superpose au motif MVVM.

  • Dans MVVM, chaque vue doit être connectée à son ViewModel.

  • Le ViewModelLocator est une approche simple pour centraliser le code et découpler davantage la vue.

  • Cela signifie qu'il n'a pas à connaître explicitement le type ViewModel et comment le construire.

  • Il existe un certain nombre d'approches différentes pour utiliser ViewModelLocator, mais ici, nous utilisons la plus similaire à celle qui fait partie du cadre PRISM.

ViewModelLocator fournit un moyen standard, cohérent, déclaratif et faiblement couplé de faire la première construction de la vue, ce qui automatise le processus de connexion de ViewModel à la vue. La figure suivante représente le processus de haut niveau de ViewModelLocator.

Step 1 - Déterminez quel type de vue est en cours de construction.

Step 2 - Identifiez le ViewModel pour ce type de vue particulier.

Step 3 - Construisez ce ViewModel.

Step 4 - Définissez Views DataContext sur ViewModel.

Pour comprendre le concept de base, jetons un œil à l'exemple simple de ViewModelLocator en continuant le même exemple du dernier chapitre. Si vous regardez le fichier StudentView.xaml, vous verrez que nous avons connecté le ViewModel de manière statique.

Maintenant, comme indiqué dans le programme suivant, commentez ce code XAML supprimez également le code de Code-behind.

<UserControl x:Class = "MVVMDemo.Views.StudentView" 
   xmlns = "http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
   xmlns:x = "http://schemas.microsoft.com/winfx/2006/xaml" 
   xmlns:mc = "http://schemas.openxmlformats.org/markup-compatibility/2006" 
   xmlns:d = "http://schemas.microsoft.com/expression/blend/2008" 
   xmlns:local = "clr-namespace:MVVMDemo.Views" 
   xmlns:viewModel = "clr-namespace:MVVMDemo.ViewModel" 
   mc:Ignorable = "d" d:DesignHeight = "300" d:DesignWidth = "300">
	
   <!--<UserControl.DataContext> 
      <viewModel:StudentViewModel/> 
   </UserControl.DataContext>-->
	
   <Grid> 
      <StackPanel HorizontalAlignment = "Left"> 
         <ItemsControl ItemsSource = "{Binding Path = Students}">
            <ItemsControl.ItemTemplate> 
               <DataTemplate> 
					
                  <StackPanel Orientation = "Horizontal">
                     <TextBox Text = "{Binding Path = FirstName, Mode = TwoWay}" 
                        Width = "100" Margin = "3 5 3 5"/> 
								
                     <TextBox Text = "{Binding Path = LastName, Mode = TwoWay}" 
                        Width = "100" Margin = "0 5 3 5"/> 
								
                     <TextBlock Text = "{Binding Path = FullName, Mode = OneWay}" 
                        Margin = "0 5 3 5"/> 
								
                  </StackPanel> 
						
               </DataTemplate> 
            </ItemsControl.ItemTemplate> 
         </ItemsControl> 
      </StackPanel> 
   </Grid>
	
</UserControl>

Créons maintenant un nouveau dossier VML et ajoutons une nouvelle classe publique ViewModelLocator qui contiendra une seule propriété attachée (propriété de dépendance) AutoHookedUpViewModel comme indiqué dans le code suivant.

public static bool GetAutoHookedUpViewModel(DependencyObject obj) { 
   return (bool)obj.GetValue(AutoHookedUpViewModelProperty); 
}

public static void SetAutoHookedUpViewModel(DependencyObject obj, bool value) { 
   obj.SetValue(AutoHookedUpViewModelProperty, value); 
}

// Using a DependencyProperty as the backing store for AutoHookedUpViewModel. 
//This enables animation, styling, binding, etc...
 
public static readonly DependencyProperty AutoHookedUpViewModelProperty =
   DependencyProperty.RegisterAttached("AutoHookedUpViewModel",
   typeof(bool), typeof(ViewModelLocator), new PropertyMetadata(false,
   AutoHookedUpViewModelChanged));

Et maintenant, vous pouvez voir une définition de propriété d'attachement de base. Pour ajouter un comportement à la propriété, nous devons ajouter un gestionnaire d'événements modifié pour cette propriété qui contient le processus automatique de connexion du ViewModel pour View. Le code pour ce faire est le suivant -

private static void AutoHookedUpViewModelChanged(DependencyObject d, 
   DependencyPropertyChangedEventArgs e) { 
   if (DesignerProperties.GetIsInDesignMode(d)) return; 
   var viewType = d.GetType(); 
   string str = viewType.FullName; 
   str = str.Replace(".Views.", ".ViewModel."); 
	
   var viewTypeName = str; 
   var viewModelTypeName = viewTypeName + "Model"; 
   var viewModelType = Type.GetType(viewModelTypeName); 
   var viewModel = Activator.CreateInstance(viewModelType);
   ((FrameworkElement)d).DataContext = viewModel; 
}

Voici l'implémentation complète de la classe ViewModelLocator.

using System; 
using System.ComponentModel; 
using System.Windows;

namespace MVVMDemo.VML { 

   public static class ViewModelLocator { 
	
      public static bool GetAutoHookedUpViewModel(DependencyObject obj) {
         return (bool)obj.GetValue(AutoHookedUpViewModelProperty); 
      }
		
      public static void SetAutoHookedUpViewModel(DependencyObject obj, bool value) { 
         obj.SetValue(AutoHookedUpViewModelProperty, value); 
      }
		
      // Using a DependencyProperty as the backing store for AutoHookedUpViewModel. 
		
      //This enables animation, styling, binding, etc...
      public static readonly DependencyProperty AutoHookedUpViewModelProperty =
         DependencyProperty.RegisterAttached("AutoHookedUpViewModel", 
         typeof(bool), typeof(ViewModelLocator), new
         PropertyMetadata(false, AutoHookedUpViewModelChanged));
		
      private static void AutoHookedUpViewModelChanged(DependencyObject d,
         DependencyPropertyChangedEventArgs e) { 
         if (DesignerProperties.GetIsInDesignMode(d)) return; 
         var viewType = d.GetType(); 
			
         string str = viewType.FullName; 
         str = str.Replace(".Views.", ".ViewModel."); 
			
         var viewTypeName = str; 
         var viewModelTypeName = viewTypeName + "Model";
         var viewModelType = Type.GetType(viewModelTypeName); 
         var viewModel = Activator.CreateInstance(viewModelType);
			
        ((FrameworkElement)d).DataContext = viewModel; 
      } 
   } 
}

La première chose à faire est d'ajouter un espace de noms afin que nous puissions accéder à ce type ViewModelLocator à la racine de notre projet. Ensuite, sur l'élément de route qui est un type de vue, ajoutez la propriété AutoHookedUpViewModel et définissez-la sur true.

xmlns:vml = "clr-namespace:MVVMDemo.VML"
vml:ViewModelLocator.AutoHookedUpViewModel = "True"

Voici l'implémentation complète du fichier StudentView.xaml.

<UserControl x:Class = "MVVMDemo.Views.StudentView" 
   xmlns = "http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
   xmlns:x = "http://schemas.microsoft.com/winfx/2006/xaml" 
   xmlns:mc = "http://schemas.openxmlformats.org/markup-compatibility/2006" 
   xmlns:d = "http://schemas.microsoft.com/expression/blend/2008" 
   xmlns:local = "clr-namespace:MVVMDemo.Views" 
   xmlns:viewModel = "clr-namespace:MVVMDemo.ViewModel" 
   xmlns:vml = "clr-namespace:MVVMDemo.VML" 
   vml:ViewModelLocator.AutoHookedUpViewModel = "True" 
   mc:Ignorable = "d" d:DesignHeight = "300" d:DesignWidth = "300">
   
   <!--<UserControl.DataContext> 
      <viewModel:StudentViewModel/> 
   </UserControl.DataContext>-->

   <Grid> 
      <StackPanel HorizontalAlignment = "Left"> 
         <ItemsControl ItemsSource = "{Binding Path = Students}"> 
            <ItemsControl.ItemTemplate> 
               <DataTemplate> 
					
                  <StackPanel Orientation = "Horizontal"> 
                     <TextBox Text = "{Binding Path = FirstName, Mode = TwoWay}" 
                        Width = "100" Margin = "3 5 3 5"/> 
								
                     <TextBox Text = "{Binding Path = LastName, Mode = TwoWay}" 
                        Width = "100" Margin = "0 5 3 5"/>
								
                     <TextBlock Text = "{Binding Path = FullName, Mode = OneWay}" 
                        Margin = "0 5 3 5"/> 
								
                  </StackPanel> 
						
               </DataTemplate> 
            </ItemsControl.ItemTemplate> 
         </ItemsControl> 
      </StackPanel>
   </Grid> 
	
</UserControl>

Lorsque le code ci-dessus est compilé et exécuté, vous verrez que ViewModelLocator connecte le ViewModel pour cette vue particulière.

Une chose clé à noter à ce sujet est que la vue n'est plus couplée en quelque sorte au type de son ViewModel ou à la façon dont il est construit. Tout cela a été déplacé vers l'emplacement central à l'intérieur du ViewModelLocator.