0

MVC\MVVM と WPF を使用しています。モデルにバインドされたフォームと、PropertyChanged イベントをキャッチし、ビジネス ルールと検証を評価するコントローラーがあります。さて、検証が false の場合にメッセージをポップアップ表示して、ユーザーに何が問題で、どのように修正するかを伝えたいと思います。しかし、コントローラーからの「正しい」方法がわかりません。ビューでキャッチできる例外をスローしたいのですが、方法がわかりません。Dispatcher.Invoke() を試しましたが、アプリケーション レベルで未処理の例外が発生しました。

コントローラーの PropertyChanged イベント ハンドラーから生成された例外をトラップするにはどうすればよいですか?

編集:具体的には、割引のリストを含むコンボボックスがあります。不適切な選択を許可することはできませんが、選択が不適切である理由をユーザーに通知する必要があります。これは、整数を含むテキストボックスほど明白ではありません。顧客がアンケートに回答した日付をユーザーに伝える必要があります。その割引を 2 回使用することはできません。リストから調査割引を除外したくありません。ユーザーにはエラーのように見えるからです。割引を提示し、顧客がその割引を使用したため、再度使用できないことを伝える必要があります。

編集 2: ValidationRule クラスを調べましたが、データベース ルックアップを使用する必要があるため、すべてをモデルに保持し、コントローラーにビジネス ルールを保持する方法がわかりません。IDataErrorInfo を見てきましたが、モデルをコントローラーにラップし、代わりにコントローラーにバインドする必要がありますが、1 つのフィールドに対してのみです。この場合の最善の方法は、コントローラーにビューのメソッドを呼び出してメッセージをポップアップさせることだと思います。

4

1 に答える 1

2

あなたは間違った道を歩いています。

MVVM で検証を処理する良い方法は、バインディングを実装IDataErrorInfoして設定ValidatesOnDataErrorsすることです。trueまた、ほぼ確実にValidatesOnExceptions、完全を期すために有効にして、プロパティをバインドしたコントロールでNotifyOnValidationErrorバインド エンジンが添付イベントをトリガーするようにすることもできます。Validation.Error

詳細については、WPFでのデータ バインディングに関する MSDN ドキュメントの「検証」セクションを参照してください。

いくつかのヒント:

  • .NET 4.5 では、と比較して強化された検証機能を提供するINotifyDataErrorInfo対応するバインディング プロパティが導入されています。あなたはそれを調べたいかもしれません。ValidatesOnNotifyDataErrorsIDataErrorInfo
  • IDataErrorInfo.Errorこれは Windows フォーム インフラストラクチャによって使用され、WPF では無視されるため、実際に内部で意味のあることを行う必要はありません。getter throw を使用することもできますNotImplementedException
  • このアプローチを説明する優れた読み物があり、例とコードが完備されてます

更新: 説明とサンプルコード

ValidationRuleこの検証モデルには、自分自身の実装はまったく含まれていません。モデル (つまり、バインディング ソース) は、2 つのインターフェイスのいずれかを実装するだけで済みます。インターフェイスの実装方法は完全にあなた次第です。過去のプロジェクトで、基本的な非同期検証を実装しました

public interface IDelegatedValidation : IDataErrorInfo
{
    /// <summary>
    /// Occurs when validation is to be performed.
    /// </summary>
    event EventHandler<DelegatedValidationEventArgs> ValidationRequested;
}

public class DelegatedValidationEventArgs : EventArgs
{
    public DelegatedValidationEventArgs(string propertyName)
    {
        this.PropertyName = propertyName;
    }

    public string PropertyName { get; private set; }

    public bool Handled { get; set; }

    public string ValidationError { get; set; }
}

モデルはIDelegatedValidation、イベントを公開することによって実装され、

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

private string GetValidationError(string propertyName)
{
    var args = new DelegatedValidationEventArgs(propertyName);
    this.OnValidationRequested(args);
    return args.ValidationError;
}

protected virtual void OnValidationRequested(DelegatedValidationEventArgs args)
{
    var handler = this.ValidationRequested;
    if (handler == null) {
        return;
    }

    foreach (EventHandler<DelegatedValidationEventArgs> target in handler.GetInvocationList()) {
        target.Invoke(this, args);
        if (args.Handled) {
            break;
        }
    }
}

したがって、ワークフローは次のようになります。

  1. モデルがビューモデルによってラップされようとしているとき、検証を実行できる適切なエンティティがそのValidationRequestedイベントにサブスクライブします。
  2. ビューはモデルにバインドされます。ある時点で検証がトリガーされます。
  3. モデルは を呼び出しますGetValidationError
  4. イベント ハンドラーは 1 つずつ呼び出されます。チェーンが停止するように、検証エラーを生成する最初のハンドラーがargs.ValidationErrorとを設定します。args.Handledtrue
  5. 検証エラーがビューに返されます。

ビューモデルがそのモデルが有効かどうかを知る必要がある場合 (たとえば、「保存」コマンドを有効/無効にするため)、このプロセスも利用する必要があるという点で、追加のひねりがあります。

/でできないことは本当にありません。なぜなら、それらをどのように実装するかは完全にあなた次第だからです。他の例については、後者のドキュメントのSilverlight バージョンを必ず確認してください。インターネット上には、このような役立つ資料もたくさんあります。IDataErrorInfoINotifyDataErrorInfo

于 2012-10-01T15:30:39.800 に答える