2009-03-17 2 views
9

私はMVVMアプリケーションを持っています。 ViewModelsの1つに、ObservableCollectionを移入する 'FindFilesCommand'があります。次に、同じViewModelで 'RemoveFilesCommand'を実装します。このコマンドを実行すると、より多くのユーザー入力を得るためのウィンドウが表示されます。モデルビューで新しいウィンドウを表示するのに最適な場所ViewModel

ここで/ MVVMパラダイムを維持しながらこれを行う最善の方法は何ですか?どういうわけか はやって:ViewModelにで

new WhateverWindow().Show()

は間違っているようです。

乾杯、この種のダイアログの

スティーブ

+0

私は[この記事](http://stackoverflow.com/a/15512972/385995)に非常によく似た質問に答えました。 –

答えて

2

個人的には、このシナリオは、メインウィンドウビューモデルがエンドユーザーが完了するためのタスクを開始したいと考えるものです。

タスクの作成と初期化は、その責任を負うべきです。ビューは、子ウィンドウを作成して表示し、タスクを新しくインスタンス化されたウィンドウのビューモデルとして使用する必要があります。

タスクをキャンセルまたはコミットできます。完了したら通知を出します。

ウィンドウは、通知を使用して自身を閉じます。親ビューモデルは、フォローアップ作業がある場合にタスクがコミットした後に通知を使用して追加作業を行います。

これは、人々がコードビハインドアプローチで行う自然/直感的な操作に近いと思われますが、サービスなどの概念的オーバーヘッドを追加することなく、UIに依存しない懸念をビューモデルに分割するようにリファクタリングしました。

私はこれをSilverlight用に実装しています。詳細については、http://www.nikhilk.net/ViewModel-Dialogs-Task-Pattern.aspxを参照してください...私はコメント/それ以上の提案を聞いて欲しいです。私たちがやっている

-1

。私はそれをFindFilesCommandのネストされたクラスとして定義します。多くのコマンドの中で使われている基本的なダイアログが、それらのコマンドにアクセス可能なモジュールで定義されており、それに応じてダイアログを設定するコマンドがあります。

コマンドオブジェクトは、ダイアログが他のソフトウェアとどのように相互作用しているかを示すのに十分です。私自身のソフトウェアでは、Commandオブジェクトは独自のライブラリに置かれ、ダイアログはシステムの他の部分から隠されています。

何かをするには、私の意見では余計なことです。さらに、最高レベルでそれを維持しようとすると、多くの余分なインターフェイスと登録メソッドを作成することがよくあります。これは、ほとんど利益を得るためのコーディングです。

フレームワークと同様に、奴隷の献身はあなたにいくつかの奇妙な路地を導きます。あなたは悪いコードのにおいを得るときに使用する他のテクニックがあるかどうかを判断するために判断を使用する必要があります。私の意見では、ダイアログは、それらを使用するコマンドの隣にしっかりと縛られ、定義されるべきです。そうすれば、5年後に私はコードのその部分に戻り、コマンドが扱っているすべてを見ることができます。

また、いくつかの例では、ダイアログは複数のコマンドに便利ですが、すべてのコマンドに共通のモジュールで定義します。しかし私のソフトウェアではおそらく20のダイアログのうち1つがこのようなものです。主な例外はファイルのオープン/セーブダイアログです。ダイアログが何十ものコマンドで使用されている場合は、インターフェースを定義し、そのインターフェースを実装してそのフォームを登録するためのフォームを作成するという完全な道を行くでしょう。

国際化のためのローカリゼーションがアプリケーションにとって重要な場合は、すべてのフォームが1つのモジュールに含まれていないので、このスキームを使用することを考慮する必要があります。

+0

こんにちは。私はViewModelの具体的なダイアログを持つことでテスト容易性が損なわれると思います。 –

0

MVVMでもこの問題が発生しました。私の最初の考えは、ダイアログを使わない方法を見つけることです。 WPFを使用すると、ダイアログを使うよりも、よりスッキリな方法を思いつくのがずっと簡単です。

これが不可能な場合は、ViewModelで共有クラスを呼び出して、ユーザーから情報を取得することをお勧めします。 ViewModelは、ダイアログが表示されていることを完全に認識していないはずです。

単純な例として、ユーザーが削除を確認する必要がある場合、ViewModelはDialogHelper.ConfirmDeletion()を呼び出すことができます。これは、ユーザーがyesまたはnoと答えたかどうかのブール値を返します。ダイアログの実際の表示はHelperクラスで行われます。

多くのデータを返す高度なダイアログでは、ヘルパーメソッドはダイアログ内のすべての情報を含むオブジェクトを返す必要があります。

残念ながらMVVMの残りの部分とスムーズにフィットしないと私は同意しますが、これ以上の例はまだ見つかりませんでした。

+0

実際にダイアログを呼び出す "DialogHelper.ConfirmDeletion()"は、何の定義もしません。あなたはまだコード内に純粋なUIを混ぜています。 (結局のところ、DialogHelperは既に窓口のヘルパーであることを示唆しています...) –

+0

私は同意しますが、私はこれを行うには良い方法はありません。このダイアログは、ViewModelから表示する必要があります。私は、少なくとも明示的にダイアログを表示していないViewModelを持っていることは良いステップだと思う。このようにして、ダイアログを再利用し、最小限の努力で強制的に置き換えることができます。 – timothymcgrath

+0

私はイベントが行く方法かもしれないと思っていますか?詳細はまだわかりませんし、純粋なMVVMにどのように適合するかはわかりません。 –

0

私は、サービスはここに行く方法だと言いたいと思います。

サービスインターフェイスは、データを返す方法を提供します。そのサービスの実際の実装では、ダイアログに何かを表示して、インターフェイスに必要な情報を得ることができます。

これをテストすると、テストでサービスインタフェースをモックでき、ViewModelは賢明ではありません。 ViewModelに関しては、サービスに何らかの情報を求め、必要な情報を受け取った。ハイメロドリゲスとカールShiffletのSouthridgeの不動産の例で

+0

こんにちは。誰がサービスを所有していただろうか?ビューまたはモデル?これらの場所のいずれかではかなり正しいとは思われません。 –

+0

サービスを所有している人はどういう意味ですか?それはシングルトンです。また、サービスが提供しているものについて考えると、それはそれが削除などを確認する必要があるので、それを呼び出すVMです。 –

+0

申し訳ありませんが、私は 'どのネームスペースでサービスインターフェイスが有効か'を意味しました。 –

1

、それらが結合したコマンドの実行部分でより具体的には、のviewmodelにウィンドウを作成している:ここ

protected void OnShowDetails (object param) 
    { 
     // DetailsWindow window = new DetailsWindow(); 
     ListingDetailsWindow window = new ListingDetailsWindow(); 
     window.DataContext = new ListingDetailsViewModel (param as Listing, this.CurrentProfile) ; 
     ViewManager.Current.ShowWindow(window, true); 
    } 

リンクある: http://blogs.msdn.com/jaimer/archive/2009/02/10/m-v-vm-training-day-sample-application-and-decks.aspx

私はそれが大きな問題ではないと思います。結局のところ、ViewModelはビューとビジネスレイヤー/データレイヤーの間の「接着剤」として機能するので、ビュー(UI)に結合するのは通常のことです...

+0

お返事ありがとうございます。これで、ViewModelには、ViewDetailsWindow(およびViewManager?)のViewへの参照があることを意味しないでしょうか。 –

+1

いいえ、ViewModelは理想的にUIテクノロジから独立している必要があります。確かにそれは接着剤ですが、具体的なビューや、可能であれば、具体的なUIスタッフやメカニックに依存することは避けてください。 – Falcon

1

Onyx(http://www.codeplex.com/wpfonyx)このための素晴らしい解決策。例として、このようなViewModelにから使用することができICommonDialogProviderサービス、見て:

ICommonFileDialogProvider provider = this.View.GetService<ICommonDialogProvider>(); 
IOpenFileDialog openDialog = provider.CreateOpenFileDialog(); 
// configure the IOpenFileDialog here... removed for brevity 
openDialog.ShowDialog(); 

これは、具体的なOpenFileDialogを使用することに非常に似ていますが、完全にテスト可能です。あなたが実際に必要とするデカップリングの量は、あなたの実装の詳細です。たとえば、あなたの場合、ダイアログを使用しているという事実を完全に隠すサービスが必要な場合があります。あなたは、あなたが利用できるいくつかのオプションがありますそのため、表示がIRemoveFilesサービスの実装を持っていることを確認する必要が

public interface IRemoveFiles 
{ 
    string[] GetFilesToRemove(); 
} 

IRemoveFiles removeFiles = this.View.GetService<IRemoveFiles>(); 
string[] files = removeFiles.GetFilesToRemove(); 

:の線に沿って何か。

Onyxはまだリリースされる予定ではありませんが、コードは完全に機能し、少なくとも参考点として使用できます。私はV1インタフェースを非常にまもなく安定化させたいと考えており、まともなドキュメントとサンプルがあるとすぐにリリースする予定です。

+0

こんにちは。 'this.View.GetService()':this.Viewが返すものは何ですか?そして、私の 'view'名前空間のどの型に対しても特定の参照が必要でしょうか?私には、MVVMを壊すように見えるでしょう - 私は間違っているかもしれません - 私は非常に新しいです –

+0

Onyxフレームワークの一部であるViewインスタンスを返します。 ViewはIServiceProviderであり、ViewElement(Viewが関連付けられている要素)へのアクセスをDependencyObjectとして提供します。 ViewElementを使用しない場合は、MVVMの原則に違反していません。 Simpleサンプルをチェックしてください。 – wekempf

0

がsomethngそのようなものです、ここで説明されているもの: http://www.codeproject.com/KB/WPF/DialogBehavior.aspx?msg=3439968#xx3439968xx

のViewModelはConfirmDeletionViewModelと呼ばれる性質を持っています。プロパティを設定すると、動作はダイアログ(モーダルかどうか)を開き、ConfirmDeletionViewModelを使用します。さらに、ユーザーがダイアログを閉じたいときに実行されるデリゲートを渡しています。これは、基本的にConfirmDeletionViewModelプロパティをnullに設定するデリゲートです。