2009-07-08 21 views
38

私は、ViewModel(実際に削除したいかどうかを確認するため)にMessageBox.Show()を呼び出してWPFアプリケーションを取得しました。 これは実際にはで動作しますが、はMVVMのグレインに反するので、ViewModelはViewで何が起こっているかを明示的に判断すべきではないからです。MVVMでMessageBox.Show()の機能をどのようにして正常に実装しましたか?

だから今、私は最高の私のMVVMアプリケーションでMessageBox.Show()機能を実装する方法を、考えていますオプション:

  1. は私がテキストでメッセージを持っている可能性があり、「よろしいです。 ..? "私のXAMLのBorderにある2つのボタンYesとNoのすべてと、テンプレートにトリガーを作成して、AreYourSureDialogueBoxIsVisibleというViewModelPropertyに基づいて折りたたんだ/表示するようにしてから、このダイアログボックスが必要なときにAreYourSureDialogueBoxIsVisibleを"true"を返し、ViewModelでDelegateCommandを介して2つのボタンを処理します。

  2. また、XAMLのトリガーでこれを処理しようとすると、実際に削除ボタンでメッセージとボタンが表示され、[はい]ボタンが実際に削除されました。

どちらのソリューションは)MessageBox.Show(と数行のコードにするために使用するもののために複雑すぎるように見えます。

MVVMアプリケーションでどのように対話ボックスを正常に実装しましたか?

+0

同様の質問:http://stackoverflow.com/questions/315180/model-view-presenter-and-modal-dialog-boxes-how-to –

答えて

5

あなたが言及した2つのうち、私はオプション#2が好ましい。ページの[削除]ボタンをクリックすると、[削除の確認ダイアログ]が表示されます。 「削除の確認ダイアログ」は実際に削除を開始します。

あなたはKarl ShifflettのWPF Line Of Business Slides and Demosをチェックしましたか?私は彼がこのようなことをするのを知っています。私はどこを覚えようとします。

EDIT:デモ#11「MVVMのデータ検証」(EditContactItemsControlSelectionViewModel.DeleteCommand)を参照してください。 KarlはViewModal(What !? :-)からポップアップを呼び出します。私はあなたのアイデアが本当に好きです。単体テストが楽になりそうです。

+0

私は最終的に溶液#1でこれを解決しました。ウィンドウをポップアップしないで、Border要素をVisibility = collapsedからVisibility = Visibleにトリガーすることで、画面の上部にBorder要素を "挿入"するだけです。 DelegateCommands:TurnOnDialogueBoxDelete、DeleteItem、CancelDialogueBoxDeleteを作成しました。 ViewModelProperties:DialogueBoxDeleteStatus、ItemIdMarkedForDeletion、およびDialogueBoxDeleteTextを作成しました。したがって、単純なMessageBox.Show()と同じくらい簡単ではありませんが、うまく動作します。最終的には、他のダイアログボックスが必要なときに、このうちのいくつかを抽象化することができます。 –

+0

それは単体テストすることができます。 :-) –

11

レスキューへのサービス。これは同様に簡単ですOnyx使用(免責事項を、私は作者だこと):実行中のアプリケーションで

public void Foo() 
{ 
    IDisplayMessage dm = this.View.GetService<IDisplayMessage>(); 
    dm.Show("Hello, world!"); 
} 

、これは間接的に(「こんにちは、世界!」)MessageBox.Showを呼び出します。テスト時に、IDisplayMessageサービスを嘲笑して、ViewModelに提供して、テスト中にこれまでに達成したいことを行うことができます。

+0

Viewに間接的にアクセスすることはMVVMの習慣に従っていると考えられますか? – VCD

+0

これは大部分では決してありませんでしたが、私は単に同意しません。ここにタイトなカップリングはありません。だから私は誰かになぜ*デザイン問題があるのか​​を示すように挑戦します。上の例のアンチパターンとは、依存関係注入の代わりにサービスロケータを使用することです。それにもかかわらず、IDisplayMessageの概念、実際の答えは、サービスロケータまたはビューに間接的にアクセスすることに依存しません。 – wekempf

0

私はただVMからそれを投げます。他の人のサービスを利用したり、メッセージボックスを投げるために自分のサービスを作成したりする必要はありません。

+6

ええ、単体テストでビューモデルをテストしている場合、どうなるでしょうか?ユーザーが「はい」または「いいえ」をクリックするのを待ってテストがブロックされますか? – esylvestre

1

私は単純なMessageBoxラッパーコントロールを作成して、純粋なMVVMソリューションで使用し、ユニットテスト機能を使用できるようにしました。詳細はVMに注入し、そしてそれがメッセージボックス(ShowMessage()など)のようなメソッドを持っています、私はちょうどインタフェース(IMessageDisplayまたは類似)を作成し、私のブログhttp://geekswithblogs.net/mukapu/archive/2010/03/12/user-prompts-messagebox-with-mvvm.aspx

mukapu

+0

リンクの解決策が壊れていて修正できます。 –

1

です。標準のメッセージボックス、または何かWPF固有のものを使用して実装することができます(私はthis one on CodePlexという人をPrajeeshと呼んでいます)。

このようにすべてが分離され、テスト可能です。

1

ViewModelからのメッセージをリッスンするビヘイビアを実装しました。 Laurent Bugnionのソリューションに基づいていますが、コードを使用しないで再利用可能なので、より洗練されていると思います。

Check it out here

1

WPF MVVM私はそうビュー(の分離コードで処理さ"MessageBoxRequested"のようなイベントを引き上げについては、とにかくそれは見るだけで、コードは何

http://slwpfmessagebox.codeplex.com/

3

をサポート

& Silverlightのメッセージボックスコードビハインドでこのコードを使用することに問題はありません)。誰がまだ読んで不満さ

+0

本当に、MVVMはモデルとビューを接続するためのものです。しかし、その見方も自分自身で行動すべきです。 – jeuxjeux20

1

念のために:

私はちょうど「通知」タイプのメッセージボックス(つまり、私はDialogResultを気にしない)、しかし、私は持っている問題に対処したいです私が読んだほとんどのソリューションは、間接的にViewの実装を選択するように強制しているようです(つまり、現在はMessageBox.Showですが、後でViewで直接非表示のパネルの可視性を試してみると、 ViewModelに渡されたINotificationインターフェイスではうまく網羅できません)。

だから私は、迅速かつ汚いのために行ってきました:

のViewModelはPropertyChangedに通知が変化して、string NotificationMessage性質を有しています。

ビューはPropertyChangedに登録されており、NotificationMessageのプロパティが表示される場合は、必要なものは何でも行います。

これは、ビューにコードビハインドがあり、PropertyChangedの名前がハードコードされていることを意味しますが、XAMLではハードコードされています。つまり、可視性のためのコンバーターや、通知がまだ表示されているかどうかを示すプロパティなどのすべてを避けることを意味します。

(確かにこれはただ限られたユースケース(ファイア・アンド・フォーゲット)のために、私はそれを拡張したい場合がありますどのように多くの考えを与えていないです。)

0

私は最近、私、この問題に出くわしましたViewModels内のMessageBox.Showを完全なMVVMの苦情メッセージボックスのメカニズムに置き換えなければなりませんでした。

これを達成するために、私はInteractionRequest<Notification>InteractionRequest<Confirmation>を対話トリガーとともに使用し、メッセージボックス用の独自のビューを作成しました。我々はのviewmodelに確認ダイアログをフックアップApp.xaml.csファイルで

私は何を実装しましたが、今の彼のリンクがkaputであることディーンチョークの答えに展開するhere

3

を公開しています。ビュー(MainWindowView.xaml)私たちはViewModelに

<Button Command="{Binding Path=DeleteCommand}" /> 

のviewmodel(MainWindowViewModel.cs)でコマンドを呼び出すボタンを持つには

protected override void OnStartup(StartupEventArgs e) 
{ 
    base.OnStartup(e); 
    var confirm = (Func<string, string, bool>)((msg, capt) => MessageBox.Show(msg, capt, MessageBoxButton.YesNo) == MessageBoxResult.Yes); 
    var window = new MainWindowView(); 
    var viewModel = new MainWindowViewModel(confirm); 
    window.DataContext = viewModel; 
    ... 
} 

は、「表示するには、デリゲートのコマンドを使用しています本気ですか?"ダイアログを開き、アクションを実行します。この例では、 thisに似ている SimpleCommandですが、ICommandの実装で行う必要があります。

private readonly Func<string, string, bool> _confirm; 

//constructor 
public MainWindowViewModel(Func<string, string, bool> confirm) 
{ 
    _confirm = confirm; 
    ... 
} 

#region Delete Command 
private SimpleCommand _deleteCommand; 
public ICommand DeleteCommand 
{ 
    get { return _deleteCommand ?? (_deleteCommand = new SimpleCommand(ExecuteDeleteCommand, CanExecuteDeleteCommand)); } 
} 

public bool CanExecuteDeleteCommand() 
{ 
    //put your logic here whether to allow deletes 
    return true; 
} 

public void ExecuteDeleteCommand() 
{ 
    bool doDelete =_confirm("Are you sure?", "Confirm Delete"); 
    if (doDelete) 
    { 
     //delete from database 
     ... 
    } 
} 
#endregion 
関連する問題