5

私は MVVM を使用しており、IDataErrorInfo を使用してビューを検証したいと考えています。

私の現在の実装には、ネストされたオブジェクトとさまざまな ViewModel が含まれています。たとえば、事業体「顧客」には事業体「住所」が含まれます。「Customer.Address」のように、ビューで Address に直接アクセスしています。Address の変更を検証するには、Address に IDataErrorInfo を実装する必要があります。

異なる Views/ViewModels で Customer または Address を使用しています。異なるビュー/ビューモデルで使用すると、異なる検証動作が発生します。したがって、Entity 自体に検証を実装するだけでは不十分です。

ViewModel で直接変更したいプロパティを公開する (エンティティを直接設定/取得する新しいプロパティを作成する) と、ViewModel が硬くなりすぎるようです。そしてかなり大きすぎる。

一部のビジネス エンティティは既に他のオブジェクトから派生しているため、基本クラスから継承することはできません (変更できないという事実)。現時点で私が目にする唯一のオプションは、ViewModel へのインターフェイスをビジネス エンティティに追加し、ビジネス エンティティの this[] 呼び出しをその ViewModel インターフェイスに転送することです。

ViewModel でこれらのネストされたオブジェクトを検証する方法に関するベスト プラクティスはありますか?

編集:検証 ビジネス オブジェクトでの検証が使用可能なアイデアとして表示されないもう 1 つの理由は、ビューとデータ エントリを検証するために、ViewModel で異なるビジネス オブジェクトが必要であることです。

4

3 に答える 3

7

私が過去にこれを行った 1 つの方法は、 Model で ValidationDelegate を公開することです。これにより、ViewModel が独自の検証コードをモデルにアタッチできるようになります。

通常、これを行うのは、Modelレイヤーをプレーン データ オブジェクトとして使用するためです。そのため、モデルは max-length や not-null などの基本的なことのみを検証し、データ モデルに固有ではない高度な検証は ViewModel で行われます。これには通常、アイテムが一意であること、ユーザーが特定の範囲に値を設定する権限を持っていること、または特定のアクションに対してのみ検証が存在する場合のようなものが含まれます。

public class CustomerViewModel
{
    // Keeping these generic to reduce code here, but it
    // should include PropertyChange notification
    public AddressModel Address { get; set; }

    public CustomerViewModel()
    {
        Address = new AddressModel();
        Address.AddValidationDelegate(ValidateAddress);
    }

    // Validation Delegate to validate Adderess
    private string ValidateAddress(object sender, string propertyName)
    {
        // Do your ViewModel-specific validation here.
        // sender is your AddressModel and propertyName 
        // is the property on the address getting validated

        // For example:
        if (propertyName == "Street1" && string.IsNullOrEmpty(Address.Street1))
            return "Street1 cannot be empty";

        return null;
    }
}

検証デリゲートに通常使用するコードは次のとおりです。

#region IDataErrorInfo & Validation Members

#region Validation Delegate

public delegate string ValidationDelegate(
    object sender, string propertyName);

private List<ValidationDelegate> _validationDelegates = 
    new List<ValidationDelegate>();

public void AddValidationDelegate(ValidationDelegate func)
{
    _validationDelegates.Add(func);
}

public void RemoveValidationDelegate(ValidationDelegate func)
{
    if (_validationDelegates.Contains(func))
        _validationDelegates.Remove(func);
}

#endregion // Validation Delegate

#region IDataErrorInfo for binding errors

string IDataErrorInfo.Error { get { return null; } }

string IDataErrorInfo.this[string propertyName]
{
    get { return this.GetValidationError(propertyName); }
}

public string GetValidationError(string propertyName)
{
    string s = null;

    foreach (var func in _validationDelegates)
    {
        s = func(this, propertyName);
        if (s != null)
            return s;
    }

    return s;
}

#endregion // IDataErrorInfo for binding errors

#endregion // IDataErrorInfo & Validation Members
于 2012-09-17T13:56:46.480 に答える
1

さまざまなビュー/ビューモデルで使用すると、さまざまな検証動作が発生します。

したがって、さまざまなビューモデルがあります。これらのビューモデルを一部のベースビューモデルから継承できない場合は、集計を使用します。

public class Address {}

public class AddressViewModel1 : IDataErrorInfo
{
  private readonly Address address;
  // other stuff here
}

public class AddressViewModel2 : IDataErrorInfo
{
  private readonly Address address;
  // other stuff here
}
于 2012-09-17T11:40:59.323 に答える
0

依存性注入を使用して、異なるビューモデルごとに顧客オブジェクトに検証サービスを注入するのはどうですか?

しかし、ビューモデルに idataerrorinfo と必要なすべてのプロパティを実装すると、よりクリーンになると思いますが、もちろん、1 倍の作業が必要です。

于 2012-09-17T13:50:30.483 に答える