2016-12-14 392 views
-1

我有一个MVVM模式和绑定集合的问题。我的视图模型提供了一个收集到的看法,但得到这个集合我用这个:MVVM和业务逻辑层

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

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

当我绑定在这个名单就好像我直接我查看绑定的模型,因为它们使用相同的参考我的看法。因此,当我编辑Car的一个属性时,可以直接编辑模型而不使用carServices验证方法。

什么是解决此问题的最佳解决方案?

我是否必须将我的模型副本公开给我的视图,以便不直接从视图编辑我的模型?

是否必须在我的模型中使用BindingList并使用我的carServices中的ListChanged来验证每个更改?

+0

可能的重复[如何构建MVVM与集合?](http://stackoverflow.com/questions/7178801/how-do-i-structure-mvvm-with-collections) –

+0

谷歌“mvvm收藏”,你会发现吨的讨论和有用的解决方案 –

回答

1

您应该直接在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类之外定义的。

0

谢谢您的回答MM8,

有了这个解决方案我要创建每类需要外界的验证一个包装。它增加了工作,在重构过程中,我们必须编辑类和包装器。

你怎么看待这个解决方案是什么:

  1. 我把我的车的名单中有约束力的列表
  2. 我的服务订阅这个列表的ListChanged事件
  3. 我的服务实现INotifyDataErrorInfo
  4. 对于此列表中的每个修改都将执行验证
  5. 如果发生错误ErrorsChanged事件被触发 视图模型会对此产生偶数t并检索错误数据。
  6. 视图模型对这个事件进行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 
    } 
} 

我的视图模型

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

你认为这是一个好的做法呢?

+0

这听起来很合理,除了它是视图模型控件,而不是应该实现INotifyDataError接口的服务。 – mm8