2013-06-14 3 views
5

でモーダルダイアログを実装する場合に依存性の注入とのServiceLocatorを交換します。私は私の最初のWPFアプリケーションを書いていますし、私は私が遭遇した問題に助けをお願いしたいと思いMVVM WPFアプリケーション

私はMVVMパターンを追跡しようとしていると私は、モーダルダイアログを実装する必要がポイントに来ました。私はいくつかの時間のためのトピックを読む/グーグルと私は解決策に落ち着くことができました。しかし、リファクタリングとき、私はサービスロケータの代替としてDI(コンストラクタ・インジェクション)を使用してに関するジレンマに遭遇しました。

私はこれらを参照するつもりです:http://pastebin.com/S6xNjtWW

私は本当にRoboblobのアプローチのように:

まず:彼はモーダルダイアログ(インターフェース)の抽象化を作成します。私はインターフェイスIModalDialogを命名し、これは、それがどのように見えるかです:

public interface IModalDialog 
{ 
    bool? DialogResult { get; set; } 
    object DataContext { get; set; } 

    void Show(); 
    bool? ShowDialog(); 
    void Close();   

    event EventHandler Closed; 
} 

第二:モーダルダイアログサービスの抽象化:

public interface IModalDialogService 
{  
    void ShowDialog<TDialogViewModel>(IModalDialog view, TDialogViewModel viewModel, Action<TDialogViewModel> onDialogClose) where TDialogViewModel : class;   
    void ShowDialog<TDialogViewModel>(IModalDialog view, TDialogViewModel viewModel) where TDialogViewModel : class;   
} 

サード: IModalDialogServiceの具体的な実装:

public class ModalDialogService : IModalDialogService 
    { 
    public void ShowDialog<TDialogViewModel>(IModalDialog view, TDialogViewModel viewModel, Action<TDialogViewModel> onDialogClose) where TDialogViewModel : class 
    { 
     // set datacontext 
     if (viewModel != null) 
     { 
      view.DataContext = viewModel; 
     } 
     ((System.Windows.Window)view).Owner = System.Windows.Application.Current.MainWindow; 
     // register 
     if (onDialogClose != null) 
     { 
      view.Closed += (sender, e) => onDialogClose(viewModel); 
     } 
     view.ShowDialog(); 
    } 


    public void ShowDialog<TDialogViewModel>(IModalDialog view, TDialogViewModel viewModel) where TDialogViewModel : class 
    { 
     this.ShowDialog(view, viewModel, null); 
    } 

第4位: IModalDialogの複数の実装があります。それぞれIModalDialogを実装してウィンドウの派生クラスです。


私は(問題を記述)質問をする前に、私は事前にこれを説明する必要があります。

のは、私は、例えば、IMessageBoxServiceのためのようないくつかのより多くのサービスを、持っているとしましょう。 は、それから私はMainWindowViewModelのコンストラクタでこれらの依存関係を宣言する必要があります:私は彼ら(手でまたはユニティのようなIOCコンテナなどを使用してのいずれか)を注入することができます

public MainWindowViewModel(IModalDialogService a,        
          IMessageBoxService b, 
          ...) 

ように。

パズルの一つ欠けている部分があるモーダルダイアログサービスを利用できるようにするために - いくつかのキーに基づいてIModalDialogの具体的な実装を解決する能力が。

彼の記事でRoboblobはのServiceLocatorパターンを使用して、パズルのこの最後のピースを解決:

public class Bootstrapper 
{ 
public static void InitializeIoc() 
    { 
    SimpleServiceLocator.SetServiceLocatorProvider(new UnityServiceLocator()); 
    SimpleServiceLocator.Instance.Register<IModalDialogService, ModalDialogService>(); 
    SimpleServiceLocator.Instance.Register<IMessageBoxService, MessageBoxService>(); 
    ...  
    SimpleServiceLocator.Instance.Register<IModalWindow, EditUserModalDialogView>(Constants.EditUserModalDialog); 
    } 

}

ので、彼のMainWindowViewModel内部の彼は単に静的なクラスが取得呼び出すとIModalDialogウィンドウの具体的な実装を解決しますキーに基づきます。

でもジョシュ・スミスは彼の記事では、同様のアプローチを使用していますが、コメントで、彼は(DI - コンストラクタ・インジェクション)がいるという有効なオプションです。

参照StackOverflowの答えも変更して使用することができ似たWindowViewLoaderServiceを説明しています。


そこで質問です - 依存性注入と(IModalDialogの具体的な実装を解決)のServiceLocatorを交換するための最良の方法だろうか?

思考の私の列車がした

  1. 一つの可能​​性だけで作成します(例えばIModalDialogResolverと呼ばれる)新しいサービスを作成するために、(原因プロジェクトは、私だけが開発した/非常に大きなされていないために)で、 IModalDialogの具象実装の新しいインスタンスを返します。すべてのサービスを手作業で注入する。

  2. 私はIOCコンテナ(ユニティ)について考えました。私はそれについての経験はない。 IModalDialogの異なる実装をUnity container =>に登録することができるので、IModalDialogResolverを記述する必要はないと思ったが、MainWindowViewModelの中でどのようにコンテナを使うのだろうか? ServiceLocationのステップに戻るので、コンストラクタへの参照を渡すことはできません。
    それでは、ブートストラッパー内の単一のコンテナを使用して、すべてのサービスを解決し、IModalDialogResolverの内部で別のサービスを使用することができると考えました。しかし、これがUnityの推奨される使用法に関する良いアイデアかどうかは分かりません。私は本当にこれを判断するにはほとんど知りません。しかし、コンテナがコンストラクタに参照を渡すのと同等のシングルトンの場合、コンテナに隠された依存関係を作成するため、これは良い考えではないことがわかります。

私が持っているメンタルブロックをもっとよく説明するには:IOCコンテナ(例えば、Unity)を使用して、インターフェイスを構築して注入したいと考えています。しかし、私は単なるコンストラクタの中にパラメータとしてIModalDialogを置くことはできません。だからおそらく私は本当にこれをサービスの中に包み込んで自分自身を実装する必要があります - しかし、(Unityがこれを箱から出すことができれば)私はそれを使うことができなければUnityを最初にそこに持つことは理にかなっていません。

私は、この1つのサービスを基本クラスに入れることをお勧めしますが、議論のために、これを考慮しません。私は本当にこれを依存性注入を使って解決する正しい方法について学びたいと思っています。

+1

依存性注入とサービスの場所は互いに排他的ではありません。依存関係注入を使用してサービスロケータを注入できます。また、MVVMでメッセージボックス/ダイアログを使用するための2つの異なるアプローチ(対話サービスと対話要求)については、これを参照してください:http://stackoverflow.com/questions/16877671/showing-a-message-box-from-the-viewmodel-is -a-violation-of-mvvm-how-to-avoid – lightbricko

+0

@lightbrickoまず、ご返信ありがとうございます。 :)私は "インタラクションサービス"を正しく理解しているので、IModalDialogResolver用のインターフェイスを作成し、インプリメンテーションを注入するのが最適でしょうか?質問:私たちがUnityをboostrapper依存性注入に使用したとしましょう。あなたがIModalDialogResolverを実装するためにUnityを使うことができると思うのですか? – kajovajo

+2

@lightbricko依存性注入とサービスの場所は、同じ問題に対する反対の解決策です。技術的には、それらは相互に排他的ではありませんが、それらを混合することによって得られるものはありません。 http://www.infoq.com/articles/Succeeding-Dependency-Injection –

答えて

4

composition rootのIoCコンテナには完全に有効であり、期待しています。

実際には、これがコンテナにアクセスする唯一の場所である必要があります。

あなたが指定した例では、それがすべて起こります。具体的な実装はコンポジションルート内のコンテナに登録されています。

ここでサービスロケータパターンの使用を置き換える必要はありません。これは、完全に有効なコンポジションルートにタイプを登録するためのメカニズムに過ぎません。

実行時の条件に基づいてモーダルダイアログサービスをインスタンス化する場合は、代わりにモデルダイアログサービスファクトリを挿入する必要があります(コンテナに実装された実装による抽象化)。メソッドを呼び出してモデルダイアログサービスを作成し、このファクトリメソッドは必要な実行時パラメータを取得します。

あなたの工場では、ランタイムパラメータに基づいて適切なモデルダイアログサービスを適切に作成することができます。あるいは、適切なモデルダイアログサービスをコンテナから解決することもできます。これにより、明らかにコンテナへの参照が必要になります。

ほとんどのコンテナは自動化されたファクトリタイプをサポートしているため、ファクトリのインターフェイスを定義するだけで済み、コンテナは自動的にコンベンションを使用してファクトリを実装します。 Castle.WindsorにはTyped Factory Facilityがあり、Unityには同等のものがあります。

+0

本当にありがとうございました。あなたの投稿は非常に参考になりました。特に、工場/自動化された工場タイプに関する部分です。私はこれが現時点で受け入れられた回答イベントと考えられると思います。 工場への注入に関する追加質問があります。私は、ファクトリインターフェイスを記述し、それを実装し、コンストラクタに注入したことが有効で完璧であることを認めます。しかし、あなたは私にユニティのオートファクトリタイプについて興味があります。私はこれに続きました(http://stackoverflow.com/questions/3825270/unity-auto-factory-with-params)SO答えとこれらの2つの記事 – kajovajo

+0

[link](http://www.sharpfellows.com/post) /Unity-IoC-Container-.aspx)、[リンク](http://ithinksharp.blogspot.cz/2010/02/unity-2-and-injectionfactory.html)。私はここに私の試みを入れました:[pastebin](http://pastebin.com/E2fkLuFh) 私はペーストビンにも私の質問を書いた(私は問題ではないことを願っています)。あなたはそれを見て、あなたの考えを教えてください。大変感謝しています。 – kajovajo

+0

私は、コンテナを介してモーダルダイアログを解決したいという理由がない限り(実際には大きな依存関係のチェーンなど)、マニュアルファクトリで作業を開始します。したがって、その場合は、ファクトリのモーダルダイアログを新規に作成し、コンテナにファクトリを登録し、ファクトリの抽象化を消費コードに渡します。 – devdigital

関連する問題