MVVM - Bağımlılık Enjeksiyonu

Bu bölümde, bağımlılık enjeksiyonu hakkında kısaca tartışacağız. İletişimin diğer ucunda neler olup bittiğini açıkça bilmeden iletişim kurmalarına olanak tanıyan veri bağlama ayrıştırıcı Görünümleri ve ViewModel'leri zaten ele aldık.

Şimdi ViewModel'imizi müşteri hizmetlerinden ayırmak için benzer bir şeye ihtiyacımız var.

Nesne yönelimli programlamanın ilk günlerinde, geliştiriciler uygulamalardaki sınıf örneklerini oluşturma ve alma sorunuyla karşı karşıya kaldılar. Bu sorun için çeşitli çözümler önerilmiştir.

Son birkaç yıldır, bağımlılık enjeksiyonu ve kontrolün tersine çevrilmesi (IoC) geliştiriciler arasında popülerlik kazandı ve Singleton modeli gibi bazı eski çözümlere göre öncelik kazandı.

Bağımlılık Enjeksiyonu / IoC Konteynerleri

IoC ve bağımlılık enjeksiyonu birbiriyle yakından ilişkili iki tasarım modelidir ve kapsayıcı temelde bu modellerin her ikisini de sizin için yapan bir altyapı kodu yığınıdır.

  • IoC modeli, inşaat için sorumluluk devretmekle ilgilidir ve bağımlılık enjeksiyon modeli, zaten oluşturulmuş bir nesneye bağımlılıklar sağlamakla ilgilidir.

  • Her ikisi de inşa etmek için iki aşamalı bir yaklaşım olarak ele alınabilir. Bir konteyner kullandığınızda, konteyner aşağıdaki gibi çeşitli sorumluluklar alır -

    • İstendiğinde bir nesne oluşturur.
    • Kap, bu nesnenin neye bağlı olduğunu belirleyecektir.
    • Bu bağımlılıkları oluşturmak.
    • Bunları inşa edilmekte olan nesneye enjekte etmek.
    • Yinelemeli olarak işlem yapmak.

ViewModels ve istemci hizmetleri arasındaki ayrışmayı kesmek için bağımlılık enjeksiyonunu nasıl kullanabileceğimize bir göz atalım. Bununla ilgili bağımlılık enjeksiyonu kullanarak kaydetme işleme AddEditCustomerViewModel formunu bağlayacağız.

Öncelikle Hizmetler klasöründeki projemizde yeni bir arayüz oluşturmamız gerekiyor. Projenizde bir hizmetler klasörünüz yoksa, önce onu oluşturun ve aşağıdaki arabirimi Hizmetler klasörüne ekleyin.

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

Aşağıda, ICustomersRepository uygulaması yer almaktadır.

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

Kaydetme işlemini yapmanın basit yolu, AddEditCustomerViewModel'e yeni bir ICustomersRepository örneği eklemek ve AddEditCustomerViewModel ve CustomerListViewModel yapıcısını aşırı yüklemektir.

private ICustomersRepository _repo; 

public AddEditCustomerViewModel(ICustomersRepository repo) { 
   _repo = repo; 
   CancelCommand = new MyIcommand(OnCancel);
   SaveCommand = new MyIcommand(OnSave, CanSave); 
}

Aşağıdaki kodda gösterildiği gibi OnSave yöntemini güncelleyin.

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

Tam AddEditCustomerViewModel aşağıdadır.

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

Yukarıdaki kod derlendiğinde ve çalıştırıldığında, aynı çıktıyı göreceksiniz, ancak şimdi ViewModel'ler daha gevşek bir şekilde ayrıştırılmış durumda.

Müşteri Ekle düğmesine bastığınızda aşağıdaki görünümü göreceksiniz. Kullanıcı herhangi bir alanı boş bıraktığında vurgulanacak ve kaydet düğmesi devre dışı bırakılacaktır.