Mvvm-dependency-injection
MVVM –依存性注入
この章では、依存性注入について簡単に説明します。 通信のもう一方の端で何が起こっているかを明確に知らずに通信できるように、ビューとViewModelを互いに分離するデータバインディングについては既に説明しました。
ここで、ViewModelをクライアントサービスから分離するのと同様のものが必要です。
オブジェクト指向プログラミングの初期の頃、開発者はアプリケーション内のクラスのインスタンスを作成および取得する問題に直面していました。 この問題に対してさまざまな解決策が提案されています。
過去数年間、依存性注入と制御の反転(IoC)は開発者の間で人気を博し、シングルトンパターンなどの古いソリューションよりも優先されてきました。
依存性注入/IoCコンテナー
IoCと依存性注入は密接に関連する2つの設計パターンであり、コンテナは基本的にこれらの両方のパターンを実行するインフラストラクチャコードのチャンクです。
- IoCパターンは、構築の責任を委任することに関するものであり、依存性注入パターンは、既に構築されているオブジェクトに依存関係を提供することです。
- どちらも、構築する2段階のアプローチとして扱うことができます。 あなたがコンテナを使用するとき、コンテナは次のようないくつかの責任を負います-
- 要求されたときにオブジェクトを構築します。
- コンテナは、そのオブジェクトが依存するものを決定します。
- これらの依存関係を構築します。
- 構築中のオブジェクトにそれらを注入します。
- プロセスを再帰的に実行します。
依存性注入を使用して、ViewModelとクライアントサービス間の分離を解除する方法を見てみましょう。 それに関連する依存関係注入を使用して、保存処理AddEditCustomerViewModelフォームを結び付けます。
最初に、プロジェクト内の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;
}
}
}
}
上記のコードをコンパイルして実行すると、同じ出力が表示されますが、ViewModelsはより緩やかに分離されます。
MVVM Dependency Injection MainWindow1
[顧客の追加]ボタンを押すと、次のビューが表示されます。 ユーザーがフィールドを空のままにすると、そのフィールドが強調表示され、保存ボタンが無効になります。