📜  MVVM –连接ViewModel

📅  最后修改于: 2020-11-19 05:22:27             🧑  作者: Mango


在本章中,我们将介绍如何连接ViewModel。这是我们讨论“视图优先”构造的最后一章的继续。现在,第一种构造的下一个形式是元模式,称为ViewModelLocator 。它是伪模式,位于MVVM模式的顶部。

  • 在MVVM中,每个视图都需要连接到其ViewModel。

  • ViewModelLocator是一种简单的方法,可以集中代码并进一步分离视图。

  • 这意味着它不必显式了解ViewModel类型以及如何构造它。

  • 有多种方法可以使用ViewModelLocator,但是这里我们使用与PRISM框架最相似的方法。

ViewModelLocator提供了一种标准的,一致的,声明性的和松散耦合的方式来进行视图优先构造,该构造自动化了将ViewModel连接到View的过程。下图表示ViewModelLocator的高级过程。

连接ViewModel

步骤1-找出正在构造的视图类型。

步骤2-识别该特定视图类型的ViewModel。

步骤3-构造该ViewModel。

步骤4-将Views DataContext设置为ViewModel。

为了理解基本概念,让我们继续上一章中的相同示例,来看看ViewModelLocator的简单示例。如果查看StudentView.xaml文件,您将看到我们已经静态连接了ViewModel。

现在,如下面的程序所示,注释这些XAML代码也将从Code-behind中删除该代码。


    
   
    
    
       
         
             
                
                    
                  
                      
                                
                      
                                
                      
                                
                   
                        
                
             
          
       
   
    

现在,我们创建一个新的文件夹VML并添加一个新的公共类ViewModelLocator,该类将包含一个附加的属性(依赖项属性)AutoHookedUpViewModel,如下面的代码所示。

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

现在,您可以看到基本的附加属性定义。要向该属性添加行为,我们需要为此属性添加一个已更改的事件处理程序,其中包含自动挂接ViewModel for View的自动过程。执行此操作的代码如下-

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

以下是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; 
      } 
   } 
}

首先要做的是添加一个名称空间,以便我们可以在项目的根目录中获得该ViewModelLocator类型。然后在作为视图类型的route元素上,添加AutoHookedUpViewModel属性并将其设置为true。

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

这是StudentView.xaml文件的完整实现。


   
   

    
       
          
             
                
                    
                   
                      
                                
                     
                                
                      
                                
                   
                        
                
             
          
      
    
    

当上面的代码被编译和执行后,您将看到ViewModelLocator正在为该特定View连接ViewModel。

连接ViewModel主窗口

需要注意的关键一点是,视图不再以某种方式与其ViewModel的类型或其构造方式耦合。所有这些都移到了ViewModelLocator内部的中央位置。