MVVM и уровень бизнес-логики

У меня проблема с шаблоном MVVM и коллекцией привязок. Моя ViewModel предоставляет коллекцию для просмотра, но для получения этой коллекции я использую это:

public BindingList<Car> BindingListCars { get; set; }

public CarsVm()
{
    BindingListVoiture = carServices.ListCars;
}

Когда я связываю свое Представление с этим списком, я как бы связываю свое Представление с моделью напрямую, потому что они используют одну и ту же ссылку. Поэтому, когда я редактирую одно свойство Car, модель редактируется напрямую без использования carServices метод проверки.

Как лучше всего решить эту проблему?

Нужно ли выставлять копию моей модели в моём виде, чтобы не редактировать мою модель напрямую из вида?

Должен ли я использовать BindingList в моей модели и подписаться на ListChanged в моем carServices проверить каждое изменение?

2 ответа

Решение

Вы должны либо выполнить проверку непосредственно в самом классе Car, либо предоставить доступ к объектам-оболочкам, вместо того, чтобы выставлять "реальные" объекты Car на просмотр.

Следующий пример кода должен дать вам представление о том, что я имею в виду:

//the "pure" model class:
public class Car
{
    public string Model { get; set; }
}


public class CarService
{
    public List<CarWrapper> ListCar()
    {
        List<Car> cars = new List<Car>(); //get your Car objects...

        return cars.Select(c => new CarWrapper(c, this)).ToList();
    }

    public bool Validate()
    {
        //
        return true;
    }
}

public class CarWrapper
{
    private readonly Car _model;
    CarService _service;
    public CarWrapper(Car model, CarService service)
    {
        _model = model;
        _service = service;
    }

    //create a wrapper property for each property of the  Car model:
    public string Model
    {
        get { return _model.Model; }
        set
        {
            if(_service.Validate())
                _model.Model = value;
        }
    }
}

Очевидно, что если вы выставите IEnumerable из вашей модели представления для привязки представления, вы фактически обойдете любую проверку, которая определена вне класса Car, если представление может установить какие-либо свойства класса Car.

Спасибо за ваш ответ мм8,

С помощью этого решения я должен создать одну оболочку для каждого класса, которая требует внешней проверки. Это добавляет работу, и во время рефакторинга мы должны отредактировать класс и Wrapper.

Что вы думаете об этом решении:

  1. Я поместил свой список транспортных средств в обязательный список
  2. Мой сервис подписался на событие ListChanged этого списка
  3. Мой сервис реализует INotifyDataErrorInfo
  4. Для каждой модификации в этом списке выполняется проверка
  5. При возникновении ошибки возникает событие ErrorsChanged. Модель представления подписывается на это событие и получает данные об ошибке.
  6. Модель представления подписывается на это событие и получает данные об ошибках.

Например:

Внедрение моих услуг:

public class VehicleServices : INotifyDataErrorInfo
{

     private BindingList<Vehicle> _bindingListCar
     public BindingList<Vehicle> BindingListCar 
     { 
         get return _bindingListCar;
     }

     private readonly Dictionary<string, ICollection<string>>
        _validationErrors = new Dictionary<string, ICollection<string>>();

     //INotifyDataErrorInfo implementation

     public IEnumerable GetErrors(string propertyName)
     public bool HasErrors
     private void RaiseErrorsChanged(string propertyName)

     public VehicleServices()
     {
         _bindingListCar = GetVehicles();
         _bindingListCar.ListChanged += BindingListVehicleChanged;
     }

     private void BindingListVehicleChanged(object sender, ListChangedEventArgs e)
     {
         //Only modification is managed
         if (e.ListChangedType != ListChangedType.ItemChanged) return;
         switch(e.PropertyDescriptor.Name)

         //Validate each property

         //if there is ErrorsChanged is raised
     }
 }

И моя ViewModel

 public class CarVm : BindableBase
 {

      private ICollection<string> _errors;

      public ICollection<string> Error
      {
         get
         {
             return _errors;
         }
         set
         {
             SetProperty(ref _errors, value);
         }
      }
      private VehicleServices _carServices;

      public BindingList<Vehicle> BindingListCar { get; set; }

      public CarVm(VehicleServices carServices)
      {
           _carServices = carServices;
           BindingListCar = new BindingList<Vehicle>(_carServices.BindingListCar);
           _carServices.ErrorsChanged += _carServices_ErrorsChanged;
       }

       private void _carServices_ErrorsChanged(object sender, DataErrorsChangedEventArgs e)
       {
           Error = _carServices.ValidationErrors[e.PropertyName];
       }
 }

Как вы думаете, это хорошая практика?

Другие вопросы по тегам