我在MVVM模式和绑定收集方面存在问题。我的ViewModel为视图提供了一个集合,但是为了获得此集合,我使用了此内容:
public BindingList<Car> BindingListCars { get; set; }
public CarsVm()
{
BindingListVoiture = carServices.ListCars;
}
当我在此列表上绑定我的视图时,就像我在模型上直接绑定我的视图一样,因为它们使用相同的参考。因此,当我编辑Car
的一个属性时,该模型将直接编辑而不使用carServices
验证方法。
纠正此问题的最佳解决方案是什么?
我是否必须将模型的副本曝光到我的视图,以免从视图直接编辑我的模型?
我是否必须在我的模型中使用BindingList
,并在carServices
中使用ListChanged
来验证每个更改?
您应该直接在汽车类本身中执行验证,或者将包装器对象暴露在内,而不是将"真实"的汽车对象公开到视图中。
以下示例代码应该使您了解我的意思:
//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&lt; car&gt;从您的视图模型以绑定到绑定的视图,如果视图能够设置汽车类的任何属性,则有效地绕过了在汽车类外部进行的任何验证。
感谢您的答案MM8,
使用此解决方案,我必须每个课程创建一个需要外部验证的包装器。它增加了工作,在重构期间,我们必须编辑课程和包装器。
您对此解决方案有何看法:
- 我将我的车辆清单放在装订列表中
- 我的服务订阅此列表的Listchanged事件
- 我的服务实施InotifyDataErrorinfo
- 对于此列表中的每次修改,执行了
- 如果提出了错误的错误事件此事件的视图模型订阅并检索错误数据。
- 此事件的视图模型subsribe并检索错误数据。
例如:
我的服务实施:
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];
}
}
您认为这是一个好习惯吗?