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
Спасибо за ваш ответ мм8,
С помощью этого решения я должен создать одну оболочку для каждого класса, которая требует внешней проверки. Это добавляет работу, и во время рефакторинга мы должны отредактировать класс и Wrapper.
Что вы думаете об этом решении:
- Я поместил свой список транспортных средств в обязательный список
- Мой сервис подписался на событие ListChanged этого списка
- Мой сервис реализует INotifyDataErrorInfo
- Для каждой модификации в этом списке выполняется проверка
- При возникновении ошибки возникает событие ErrorsChanged. Модель представления подписывается на это событие и получает данные об ошибке.
- Модель представления подписывается на это событие и получает данные об ошибках.
Например:
Внедрение моих услуг:
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];
}
}
Как вы думаете, это хорошая практика?