![MVVM Tutorial](/mvvm/images/mvvm-mini-logo.jpg)
- MVVM 教程
- MVVM - 首页
- MVVM – 简介
- MVVM - 优点
- MVVM - 职责
- MVVM - 第一个应用程序
- MVVM - 连接视图
- MVVM - 连接 ViewModel
- MVVM - WPF 数据绑定
- MVVM - WPF 数据模板
- MVVM - ViewModel 通信
- MVVM - 层次结构与导航
- MVVM - 验证
- MVVM - 依赖注入
- MVVM - 事件
- MVVM - 单元测试
- MVVM - 框架
- MVVM - 面试问题
- MVVM 有用资源
- MVVM - 快速指南
- MVVM - 有用资源
- MVVM - 讨论
MVVM – 依赖注入
在本章中,我们将简要讨论依赖注入。我们已经介绍了数据绑定将视图和 ViewModel 解耦,使它们能够在彼此不知道对方通信细节的情况下进行通信。
现在我们需要类似的东西来解耦我们的 ViewModel 和客户端服务。
在面向对象编程的早期,开发人员面临着在应用程序中创建和检索类实例的问题。针对此问题提出了各种解决方案。
在过去的几年里,依赖注入和控制反转 (IoC) 在开发人员中越来越受欢迎,并取代了一些较旧的解决方案,例如单例模式。
依赖注入/IoC 容器
IoC 和依赖注入是两种紧密相关的设计模式,容器基本上是一块基础设施代码,可以为您完成这两种模式。
IoC 模式是关于委托构造的责任,而依赖注入模式是关于向已构造的对象提供依赖项。
它们都可以被视为构造的两阶段方法。当您使用容器时,容器承担以下几个责任:
- 在被请求时构造对象。
- 容器将确定该对象依赖于什么。
- 构造这些依赖项。
- 将它们注入到正在构造的对象中。
- 递归地执行此过程。
让我们看看如何使用依赖注入来打破 ViewModel 和客户端服务之间的解耦。我们将使用与之相关的依赖注入来连接 AddEditCustomerViewModel 形式的保存处理。
首先,我们需要在我们的项目中的 Services 文件夹中创建一个新的接口。如果您的项目中没有 Services 文件夹,则首先创建它,然后在 Services 文件夹中添加以下接口。
using MVVMHierarchiesDemo.Model; using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace MVVMHierarchiesDemo.Services { public interface ICustomersRepository { Task<List<Customer>> GetCustomersAsync(); Task<Customer> GetCustomerAsync(Guid id); Task<Customer> AddCustomerAsync(Customer customer); Task<Customer> UpdateCustomerAsync(Customer customer); Task DeleteCustomerAsync(Guid customerId); } }
以下是 ICustomersRepository 的实现。
using MVVMHierarchiesDemo.Model; using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace MVVMHierarchiesDemo.Services { public class CustomersRepository : ICustomersRepository { ZzaDbContext _context = new ZzaDbContext(); public Task<List<Customer>> GetCustomersAsync() { return _context.Customers.ToListAsync(); } public Task<Customer> GetCustomerAsync(Guid id) { return _context.Customers.FirstOrDefaultAsync(c => c.Id == id); } public async Task<Customer> AddCustomerAsync(Customer customer){ _context.Customers.Add(customer); await _context.SaveChangesAsync(); return customer; } public async Task<Customer> UpdateCustomerAsync(Customer customer) { if (!_context.Customers.Local.Any(c => c.Id == customer.Id)) { _context.Customers.Attach(customer); } _context.Entry(customer).State = EntityState.Modified; await _context.SaveChangesAsync(); return customer; } public async Task DeleteCustomerAsync(Guid customerId) { var customer = _context.Customers.FirstOrDefault(c => c.Id == customerId); if (customer != null) { _context.Customers.Remove(customer); } await _context.SaveChangesAsync(); } } }
执行保存处理的简单方法是在 AddEditCustomerViewModel 中添加 ICustomersRepository 的新实例,并重载 AddEditCustomerViewModel 和 CustomerListViewModel 构造函数。
private ICustomersRepository _repo; public AddEditCustomerViewModel(ICustomersRepository repo) { _repo = repo; CancelCommand = new MyIcommand(OnCancel); SaveCommand = new MyIcommand(OnSave, CanSave); }
更新 OnSave 方法,如下面的代码所示。
private async void OnSave() { UpdateCustomer(Customer, _editingCustomer); if (EditMode) await _repo.UpdateCustomerAsync(_editingCustomer); else await _repo.AddCustomerAsync(_editingCustomer); Done(); } private void UpdateCustomer(SimpleEditableCustomer source, Customer target) { target.FirstName = source.FirstName; target.LastName = source.LastName; target.Phone = source.Phone; target.Email = source.Email; }
以下是完整的 AddEditCustomerViewModel。
using MVVMHierarchiesDemo.Model; using MVVMHierarchiesDemo.Services; using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace MVVMHierarchiesDemo.ViewModel { class AddEditCustomerViewModel : BindableBase { private ICustomersRepository _repo; public AddEditCustomerViewModel(ICustomersRepository repo) { _repo = repo; CancelCommand = new MyIcommand(OnCancel); SaveCommand = new MyIcommand(OnSave, CanSave); } private bool _EditMode; public bool EditMode { get { return _EditMode; } set { SetProperty(ref _EditMode, value); } } private SimpleEditableCustomer _Customer; public SimpleEditableCustomer Customer { get { return _Customer; } set { SetProperty(ref _Customer, value); } } private Customer _editingCustomer = null; public void SetCustomer(Customer cust) { _editingCustomer = cust; if (Customer != null) Customer.ErrorsChanged -= RaiseCanExecuteChanged; Customer = new SimpleEditableCustomer(); Customer.ErrorsChanged += RaiseCanExecuteChanged; CopyCustomer(cust, Customer); } private void RaiseCanExecuteChanged(object sender, EventArgs e) { SaveCommand.RaiseCanExecuteChanged(); } public MyIcommand CancelCommand { get; private set; } public MyIcommand SaveCommand { get; private set; } public event Action Done = delegate { }; private void OnCancel() { Done(); } private async void OnSave() { UpdateCustomer(Customer, _editingCustomer); if (EditMode) await _repo.UpdateCustomerAsync(_editingCustomer); else await _repo.AddCustomerAsync(_editingCustomer); Done(); } private void UpdateCustomer(SimpleEditableCustomer source, Customer target) { target.FirstName = source.FirstName; target.LastName = source.LastName; target.Phone = source.Phone; target.Email = source.Email; } private bool CanSave() { return !Customer.HasErrors; } private void CopyCustomer(Customer source, SimpleEditableCustomer target) { target.Id = source.Id; if (EditMode) { target.FirstName = source.FirstName; target.LastName = source.LastName; target.Phone = source.Phone; target.Email = source.Email; } } } }
编译并执行上述代码后,您将看到相同的输出,但现在 ViewModel 的耦合度更低了。
![MVVM Dependency Injection MainWindow1](/mvvm/images/mvvm_dependency_injection_mainwindow1.jpg)
当您按下“添加客户”按钮时,您将看到以下视图。当用户留空任何字段时,它将突出显示,并且保存按钮将被禁用。
![MVVM Dependency Injection MainWindow2](/mvvm/images/mvvm_dependency_injection_mainwindow2.jpg)