-1

MVVM パターンとバインディング コレクションに問題があります。私のViewModelはビューにコレクションを提供しますが、このコレクションを取得するにはこれを使用します:

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

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

このリストにビューをバインドすると、同じ参照を使用するため、モデルにビューを直接バインドするかのようになります。そのため、 の1 つのプロパティを編集すると、検証メソッドCarを使用せずにモデルが直接編集されます。carServices

この問題を解決するための最良の解決策は何ですか?

ビューからモデルを直接編集しないようにするには、モデルのコピーをビューに公開する必要がありますか?

各変更を検証するにはBindingList、自分のモデルで使用し、自分でサブスクライブする必要がありますか?ListChangedcarServices

4

2 に答える 2

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 クラスのプロパティを設定できる場合、Car クラスの外部で定義されている検証を効果的にバイパスします。

于 2016-12-14T11:24:34.050 に答える
0

mm8 さん、ご回答ありがとうございます。

このソリューションでは、外部検証が必要なクラスごとに 1 つのラッパーを作成する必要があります。作業が追加され、リファクタリング中にクラスとラッパーを編集する必要があります。

このソリューションについてどう思いますか :

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

これは良い習慣だと思いますか?

于 2016-12-14T17:35:37.317 に答える