2012-02-05 17 views
6

私のWinFormsアプリケーションのMVVM(Model View ViewModel)パターンを実装しようとしています。私はC#2005を使用しています。WinFormアプリケーションのMVVM実装

私のアプリケーションには、2行のテキストボックスと3つのボタンがあるメインフォーム(ビュー)があります。第1のテキストボックスの目的は、ボタンがクリックされたときに、アプリケーションが何をしているのかに関する実行中の解説を表示することです。私は何が起こっているのユーザーを更新するTextBoxに行を追加し続ける。 2番目のテキストボックスの目的は、エラー状態、競合、重複する値についてユーザーを更新することです。要するに、ユーザーがレビューするために必要なもの。各メッセージは、INFOまたはWARNINGまたはERRORのいずれかとして分類されます。 3つのボタンのそれぞれはアクションを実行し、2つのテキストボックスを更新し続けます。

私はMainFormViewModelクラスを作成しました。

1番目の質問: ユーザーがMainFormのボタンをクリックすると、2つのテキストボックスの内容を消去し、最初の操作が完了するまでもう一度クリックできないようにボタンを無効にする必要があります。 MainFormでこのテキストボックスとボタンの更新を直接行うか、何らかの方法でMainFormViewModelを使用する必要がありますか?

2番目の質問: ボタンクリックは、MainFormViewModelクラスのメソッドを呼び出します。メソッドを呼び出す前に、メソッドを呼び出した後、最初のテキストボックスに「操作Aの開始/終了」のようなメッセージを表示します。私は、TextBoxやファイル、またはその両方にメッセージを記録するLogメソッドを持つCommonクラスを呼び出すことでこれを行います。 MainFormから直接これを行うのもいいですか?このロギングメソッドは、イベントハンドラの開始時と終了時に呼び出されます。

3番目の質問: エラーメッセージをViewModelからビューに伝播する方法を教えてください。カスタム例外クラス "TbtException"を作成しました。だから、各ボタンに2つのキャッチブロックを書く必要がありますか?1つはTbtException、もう1つは遺伝的Exceptionクラスです。

ありがとうございました。

答えて

3

ビュー内の操作は、ViewModelオブジェクトの状態に関してのみ行う必要があります。例えば。ボタンをクリックしたときにビューモデルが計算されていると仮定してはいけませんが、ビューモデルに状態を追加して、何か長いことをしてからその状態をビューで認識するようにしてください。ビュー内のボタンを無効にしたり有効にしたりしないでください。ただし、これらのボタンを変更する必要がある状態がある場合に限ります。これは、リストのどの項目が現在選択されているかを示すプロパティを持つため、UIはリストコントロールのSelectedItemメンバーを呼び出さず、ビューモデルを呼び出します。また、ユーザーが削除をクリックすると、ビューモデルによって選択されたメンバーがリストから削除され、ビューの状態がイベントの形で自動的に更新されます。

ビューのビューモデルと呼ぶものを次に示します。これは、ビューがバインドできる観測可能なコレクション(つまり、WinFormsではバインディングがうまくサポートされていないため、イベントハンドラを登録する)を介してメッセージを公開します。テキストボックスはいつでもコレクションの内容のみをレンダリングします。ビューに呼び出すことができるコレクションをクリアするアクションがあります。ビューは基になるモデルのアクションを呼び出すこともできますが、ビューモデルのみで更新する必要があります。ビューは、基になるモデルによって公開されるイベントのイベントハンドラを決して登録するべきではありません。これを行うには、そのイベントをビューモデルに接続し、そのビューに表示する必要があります。時には、それはあなたのような非常に簡単なアプリケーションでは過度のことかもしれない "間接的なレベルの間接"のように感じるかもしれません。

public class MainFormViewModel : INotifyPropertyChanged { 
    private object syncObject = new object(); 

    private MainFormModel model; 
    public virtual MainFormModel Model { 
    get { return model; } 
    set { 
     bool changed = (model != value); 
     if (changed && model != null) DeregisterModelEvents(); 
     model = value; 
     if (changed) { 
     OnPropertyChanged("Model"); 
     if (model != null) RegisterModelEvents(); 
     } 
    } 
    } 

    private bool isCalculating; 
    public bool IsCalculating { 
    get { return isCalculating; } 
    protected set { 
     bool changed = (isCalculating != value); 
     isCalculating = value; 
     if (changed) OnPropertyChanged("IsCalculating"); 
    } 
    } 

    public ObservableCollection<string> Messages { get; private set; } 
    public ObservableCollection<Exception> Exceptions { get; private set; } 

    protected MainFormViewModel() { 
    this.Messages = new ObservableCollection<string>(); 
    this.Exceptions = new ObservableCollection<string>(); 
    } 

    public MainFormViewModel(MainFormModel model) 
    : this() { 
    Model = model; 
    } 

    protected virtual void RegisterModelEvents() { 
    Model.NewMessage += new EventHandler<SomeEventArg>(Model_NewMessage); 
    Model.ExceptionThrown += new EventHandler<OtherEventArg>(Model_ExceptionThrown); 
    } 

    protected virtual void DeregisterModelEvents() { 
    Model.NewMessage -= new EventHandler<SomeEventArg>(Model_NewMessage); 
    Model.ExceptionThrown -= new EventHandler<OtherEventArg>(Model_ExceptionThrown); 
    } 

    protected virtual void Model_NewMessage(object sender, SomeEventArg e) { 
    Messages.Add(e.Message); 
    } 

    protected virtual void Model_ExceptionThrown(object sender, OtherEventArg e) { 
    Exceptions.Add(e.Exception); 
    } 

    public virtual void ClearMessages() { 
    lock (syncObject) { 
     IsCalculating = true; 
     try { 
     Messages.Clear(); 
     } finally { IsCalculating = false; } 
    } 
    } 

    public virtual void ClearExceptions() { 
    lock (syncObject) { 
     IsCalculating = true; 
     try { 
     Exceptions.Clear(); 
     } finally { IsCalculating = false; } 
    } 
    } 

    public event PropertyChangedEventHandler PropertyChanged; 
    protected virtual void OnPropetyChanged(string property) { 
    var handler = PropertyChanged; 
    if (handler != null) handler(this, new PropertyChangedEventArgs(property)); 
    } 
} 

編集:私はむしろビューよりもViewModelにで例外をキャッチします

例外処理について。ビューモデルは、表示の準備に適しています。私はそれがどのようにWPFで動作するのかわかりません。私はまだWPFでアプリケーションをプログラムしていますが、私たちはたくさんのWinFormsをやっています。

意見は異なるかもしれませんが、一般的なtry/catch節は実際には例外処理ではないと思います。私はむしろあなたのUIを非常にうまくテストし、必要な場合にのみ例外処理を含めるべきだと思います。これは、あなたのビューモデルを単体テストし、ユーザーがビューをテストする理由です。しかし、実際に原則に固執し、ビュー内のロジックを避けるならば、単体テストで多くのことを行うことができます。

+0

非常に有益で役立ちます。ありがとう!! – AllSolutions

+0

1番目の質問については、ViewがViewModelを呼び出して状態プロパティを更新し、2つのテキストボックスがこのプロパティにフックして自分自身をクリアする必要があると言っていますか? 2番目の質問については、テキストボックスがどのように実行中の解説を維持すべきか、まだ明確ではありません。 ViewModelは変数に実行中の解説を書き続けなければならないようだし、TextBoxはその変数にフックして更新を続けなければならないのだろうか?申し訳ありませんが、私はこれを初めて実装していますので、少し助けていただければ幸いです。実行中の解説テキストは非常に長くなることに注意してください。どのフォームの例ですか? – AllSolutions

+0

エラー処理に関して、フォームはtry catchブロックを持たないでしょうか? – AllSolutions

関連する問題