MVVM&业务逻辑层

时间:2016-12-14 08:41:30

标签: wpf mvvm collections binding bll

我遇到MVVM模式和绑定集合的问题。我的ViewModel为View提供了一个集合,但为了获得这个集合,我使用了它:

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

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

当我在此列表上绑定我的视图时,它就像我直接绑定模型上的View一样,因为它们使用相同的引用。因此,当我编辑Car的一个属性时,不使用carServices验证方法直接编辑模型。

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

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

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

2 个答案:

答案 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。

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

  1. 我将车辆清单列入装订清单
  2. 我的服务订阅此列表的ListChanged事件
  3. 我的服务工具INotifyDataErrorInfo
  4. 对于此列表中的每个修改,都会执行验证
  5. 如果出现错误,则会引发ErrorsChanged事件 视图模型将附加到此事件并检索错误数据。
  6. 视图模型属于此事件并检索错误数据。
  7. 例如:

    我的服务实施:

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

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