5

私はモデルを持っています:

public class Product
{
    public int Rating { get; set; }
    ...
}

およびビュー モデル:

public class ProductViewModel: IDataErrorProvider
{
    public int Temperature { get; set; }
    public Product CurrentProduct { get; set; }

    public string this[string columnName]
    {
        get
        {
            if (columnName == "Rating")
            {
                if (CurrentProduct.Rating > Temperature)
                    return "Rating is too high for current temperature";
            }
            return null;
        }
    }
}

私のビューには、DataContext として ProductViewModel のインスタンスがあります。ビューには次のフィールドがあります。

<TextBox Text={Binding Path=CurrentProduct.Rating, ValidatesOnDataErrors=True} .../>

デフォルトでは、DataContext (ProductViewModel) ではなく、バインドされたオブジェクト (Product) の IDataErrorProvider で検証が行われます。したがって、上記の例では、ProductViewModel 検証は呼び出されません。これは単純な例ですが、問題を示しています。モデルは温度を認識していない (そして認識すべきではない) ため、設計では、VM がそのフィールドで検証を実行する必要があります。

はい、それをハックして、モデルのバインドされたプロパティを ViewModel に直接複製することはできますが、呼び出しをモデルではなく VM にリダイレクトする簡単な方法が必要だと思いましたか?

4

2 に答える 2

2

ビューモデルで IDataErrorInfo によって「Rating」という名前のプロパティを検証する場合、ビューモデルには実際に Rating というプロパティが必要であり、それにバインドする必要があります。これは、ビューモデルでモデルのバインドされたプロパティを複製することを意味します。

いずれにせよ、このブログ記事(MVVM でのビジネス ルールの検証) は興味深いものになる可能性があります。作成者は、ビューモデルが設定できるモデルに Validation デリゲートを追加します。これにより、例の温度など、未知のデータを使用してモデルを検証できます。

于 2012-10-09T07:49:19.260 に答える
1

私は以前にその問題に遭遇しました。私の解決策はModels、クラスの検証時にチェックされる検証デリゲートを my から公開することです。これを使用して、それ自体ViewModelに関係のないクラスに追加の検証をフックできます。Model

たとえば、 から次のようなコードを使用して、いつでもそのセットViewModelに検証デリゲートをアタッチします。Model

public class ProductViewModel
{
    public int Temperature { get; set; }

    private product _currentProduct;
    public Product CurrentProduct 
    { 
        get { return _currentProduct; }
        set
        {
            if (value != _currentProduct)
            {
                if (_currentProduct != null)
                    _currentProduct.RemoveValidationDelegate(ValidateProduct);

                _currentProduct = value;

                if (_currentProduct != null)
                    _currentProduct.AddValidationDelegate(ValidateProduct);

                RaisePropertyChanged("CurrentProduct");
            }
        }
    }

    // Product Validation Delegate to verify temperature
    private string ValidateProduct(object sender, string propertyName)
    {
        if (propertyName == "Rating")
        {
            if (CurrentProduct.Rating > Temperature)
                return "Rating is too high for current temperature";
        }

        return null;
    }
}

ValidationDelegateに を追加する実際のコードModelは非常に一般的です。そのため、通常、BaseViewModelすべてのモデルにこの機能を持たせることができるように、モデルごとに入力する必要はありません。

#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-10-10T19:57:17.380 に答える