📜  MVVM –视图/ ViewModel通信

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


在本章中,我们将学习如何向MVVM应用程序添加交互性以及如何干净地调用逻辑。您还将看到,所有这些都是通过保持松耦合和良好的结构来完成的,这是MVVM模式的核心。要了解所有这些,首先让我们了解命令。

通过命令进行View / ViewModel通信

命令模式已被很好地记录下来,几十年来经常使用设计模式。在这种模式下,有两个主要参与者,调用者和接收者。

View和ViewModel通讯

召唤者

  • 调用程序是一段可以执行命令式逻辑的代码。

  • 通常,它是用户在UI框架的上下文中与之交互的UI元素。

  • 它可能只是应用程序中其他地方的另一段逻辑代码。

接收者

  • 接收方是在调用方激发时旨在执行的逻辑。

  • 在MVVM的上下文中,接收器通常是ViewModel中需要调用的方法。

在这两者之间,您有一个阻塞层,这意味着调用者和接收者不必显式地彼此了解。通常将其表示为暴露给调用者的接口抽象,并且该接口的具体实现能够调用接收者。

让我们看一个简单的示例,在该示例中,您将学习命令以及如何使用它们在View和ViewModel之间进行通信。在本章中,我们将继续上一章中的相同示例。

在StudentView.xaml文件中,我们有一个ListBox,它连接ViewModel中的学生数据。现在,我们添加一个按钮,用于从列表框中删除学生。

重要的是使用按钮上的命令非常容易,因为它们具有可挂接到ICommand的command属性。

因此,我们可以在ViewModel上公开一个具有ICommand的属性,并通过按钮的command属性将其绑定,如以下代码所示。


让我们在您的项目中添加一个新类,该类将实现ICommand接口。以下是ICommand接口的实现。

using System; 
using System.Windows.Input;

namespace MVVMDemo { 

   public class MyICommand : ICommand { 
      Action _TargetExecuteMethod; 
      Func _TargetCanExecuteMethod;
        
      public MyICommand(Action executeMethod) {
         _TargetExecuteMethod = executeMethod; 
      }
        
      public MyICommand(Action executeMethod, Func canExecuteMethod){ 
         _TargetExecuteMethod = executeMethod;
         _TargetCanExecuteMethod = canExecuteMethod; 
      }
        
      public void RaiseCanExecuteChanged() { 
         CanExecuteChanged(this, EventArgs.Empty); 
      }
        
      bool ICommand.CanExecute(object parameter) { 
        
         if (_TargetCanExecuteMethod != null) { 
            return _TargetCanExecuteMethod(); 
         } 
            
         if (_TargetExecuteMethod != null) { 
            return true; 
         } 
            
         return false; 
      }
        
      // Beware - should use weak references if command instance lifetime 
         is longer than lifetime of UI objects that get hooked up to command 
            
      // Prism commands solve this in their implementation 
      public event EventHandler CanExecuteChanged = delegate { };
        
      void ICommand.Execute(object parameter) { 
         if (_TargetExecuteMethod != null) {
            _TargetExecuteMethod(); 
         } 
      } 
   } 
}

如您所见,这是ICommand的简单委托实现,我们有两个委托,一个代表executeMethod,一个代表canExecuteMethod,可以在构造中传递。

在上面的实现中,有两个重载的构造函数,一个仅用于executeMethod,一个同时用于executeMethod和cancanMethod。

让我们在StudentView Model类中添加MyICommand类型的属性。现在我们需要在StudentViewModel中构造一个实例。我们将使用带有两个参数的MyICommand的重载构造函数。

public MyICommand DeleteCommand { get; set;} 

public StudentViewModel() { 
   LoadStudents(); 
   DeleteCommand = new MyICommand(OnDelete, CanDelete); 
}

现在添加OnDelete和CanDelete方法的实现。

private void OnDelete() { 
   Students.Remove(SelectedStudent); 
}

private bool CanDelete() { 
   return SelectedStudent != null; 
}

我们还需要添加一个新的SelectedStudent,以便用户可以从ListBox中删除Selected Item。

private Student _selectedStudent;
 
public Student SelectedStudent { 
   get { 
      return _selectedStudent; 
   } 
    
   set { 
      _selectedStudent = value;
      DeleteCommand.RaiseCanExecuteChanged(); 
   } 
}

以下是ViewModel类的完整实现。

using MVVMDemo.Model; 

using System.Collections.ObjectModel; 
using System.Windows.Input; 
using System;

namespace MVVMDemo.ViewModel { 

   public class StudentViewModel { 
    
      public MyICommand DeleteCommand { get; set;} 
        
      public StudentViewModel() { 
         LoadStudents(); 
         DeleteCommand = new MyICommand(OnDelete, CanDelete); 
      }
        
      public ObservableCollection Students { 
         get; 
         set; 
      }
        
      public void LoadStudents() { 
         ObservableCollection students = new ObservableCollection();
            
         students.Add(new Student { FirstName = "Mark", LastName = "Allain" }); 
         students.Add(new Student { FirstName = "Allen", LastName = "Brown" }); 
         students.Add(new Student { FirstName = "Linda", LastName = "Hamerski" }); 
            
         Students = students; 
      }
        
      private Student _selectedStudent; 
        
      public Student SelectedStudent { 
         get {
            return _selectedStudent; 
         } 
            
         set { 
            _selectedStudent = value;
            DeleteCommand.RaiseCanExecuteChanged(); 
         } 
      }
        
      private void OnDelete() { 
         Students.Remove(SelectedStudent); 
      }
        
      private bool CanDelete() { 
         return SelectedStudent != null; 
      }
   } 
}

在StudentView.xaml中,我们需要在ListBox中添加SelectedItem属性,该属性将绑定到SelectStudent属性。


以下是完整的xaml文件。


    
    
       
        
          
            
             
                    
             
                    
             
                    
          
            
       
   
    
    
       
          
                
          
       
   
    

编译并执行上述代码后,您将看到以下窗口。

View和ViewModel通讯MainWindow1

您会看到删除按钮被禁用。当您选择任何项目时,它将启用。

View和ViewModel通讯MainWindow2

选择任何项目并按Delete键。您将看到所选项目列表已删除,并且删除按钮再次变为禁用状态。

View和ViewModel通讯MainWindow3

我们建议您逐步执行上述示例,以更好地理解。