【问题标题】:MVVM & business logic LayerMVVM & 业务逻辑层
【发布时间】:2017-04-29 12:28:21
【问题描述】:

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

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

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

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

纠正这个问题的最佳解决方案是什么?

我是否必须向我的视图公开我的模型的副本才能不直接从视图中编辑我的模型?

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

【问题讨论】:

标签: wpf mvvm collections binding bll


【解决方案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 类之外指定的任何验证。

【讨论】:

    【解决方案2】:

    感谢mm8的回答,

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

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

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

    例如:

    我的服务实现:

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

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

    【讨论】:

    • 这听起来很合理,只是它是视图模型控件而不是应该实现 INotifyDataError 接口的服务。
    猜你喜欢
    • 2010-12-18
    • 2013-02-12
    • 2011-12-03
    • 2011-11-26
    • 2016-08-12
    • 2014-09-04
    • 2013-02-18
    • 1970-01-01
    • 2017-08-08
    相关资源
    最近更新 更多