我遇到MVVM模式和绑定集合的问题。我的ViewModel为View提供了一个集合,但为了获得这个集合,我使用了它:
public BindingList<Car> BindingListCars { get; set; }
public CarsVm()
{
BindingListVoiture = carServices.ListCars;
}
当我在此列表上绑定我的视图时,它就像我直接绑定模型上的View一样,因为它们使用相同的引用。因此,当我编辑Car
的一个属性时,不使用carServices
验证方法直接编辑模型。
解决此问题的最佳解决方案是什么?
我是否必须将我的模型副本公开给我的视图,以便不直接从视图中编辑我的模型?
我是否必须在我的模型中使用BindingList
并在我的ListChanged
中使用carServices
来验证每项更改?
答案 0 :(得分:1)
您应该直接在Car类本身中执行验证,或者公开包装器对象,而不是暴露&#34; real&#34;汽车对象的视图。
以下示例代码应该让您了解我的意思:
//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;从视图的视图模型到绑定,如果视图能够设置Car类的任何属性,则实际上绕过了Car类之外的任何验证。
答案 1 :(得分:0)
感谢您的回答mm8,
使用此解决方案,我必须为每个类创建一个需要外部验证的包装器。它增加了工作,在重构过程中我们必须编辑类和Wrapper。
您对此解决方案有何看法:
例如:
我的服务实施:
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];
}
}
你认为这是一个好习惯吗?