MVVM 和业务逻辑层



我在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,

使用此解决方案,我必须每个课程创建一个需要外部验证的包装器。它增加了工作,在重构期间,我们必须编辑课程和包装器。

您对此解决方案有何看法:

  1. 我将我的车辆清单放在装订列表中
  2. 我的服务订阅此列表的Listchanged事件
  3. 我的服务实施InotifyDataErrorinfo
  4. 对于此列表中的每次修改,执行了
  5. 如果提出了错误的错误事件此事件的视图模型订阅并检索错误数据。
  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
     }
 }

和我的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];
       }
 }

您认为这是一个好习惯吗?

最新更新