2013-03-05 7 views
6

MVVMパターンに従うWPFアプリケーションを開発しています。モーダルダイアログを表示するために、私は次の記事の示唆に従っています。 http://www.codeproject.com/Articles/36745/Showing-Dialogs-When-Using-the-MVVM-Pattern?fid=1541292&fr=26#xx0xxサービスロケータを使用したMVVMモーダルダイアログ

しかし、DialogServiceインターフェイスのShowDialogメソッドがMainWindowViewModelから呼び出されていることがわかりました。

私のアプリケーションの状況は少し異なります。 MainWindow.xamlには、ボタンが含まれているChildViewというユーザーコントロールが含まれています。 MainWindowViewModelには、ChildViewとバインドされているChildVMとは別のViewModelが含まれています。 ChildVMにはAddCommandが含まれており、AddCommandに対応するAddExecuteメソッド が呼び出されると、モーダルダイアログを表示する必要があります。 これをどのように達成できますか?

編集コード

 private Window FindOwnerWindow(object viewModel) 
      { 
        FrameworkElement view = null; 

     // Windows and UserControls are registered as view. 
     // So all the active windows and userControls are contained in views 
     foreach (FrameworkElement viewIterator in views) 
     { 
      // Check whether the view is an Window 
      // If the view is an window and dataContext of the window, matches 
      // with the viewModel, then set view = viewIterator 
      Window viewWindow = viewIterator as Window; 
      if (null != viewWindow) 
      { 
       if (true == ReferenceEquals(viewWindow.DataContext, viewModel)) 
       { 
        view = viewWindow; 
        break; 
       } 

      } 
      else 
      { 
       // Check whether the view is an UserControl 
       // If the view is an UserControl and Content of the userControl, matches 
       // with the viewModel, then set view = userControl 
       // In case the view is an user control, then find the Window that contains the 
       // user control and set it as owner 
       System.Windows.Controls.UserControl userControl = viewIterator as System.Windows.Controls.UserControl; 
       if (null != userControl) 
       { 
        if (true == ReferenceEquals(userControl.Content, viewModel)) 
        { 
         view = userControl; 
         break; 
        } 

       } 
      } 
     } 
     if (view == null) 
     { 
      throw new ArgumentException("Viewmodel is not referenced by any registered View."); 
     } 

     // Get owner window 
     Window owner = view as Window; 
     if (owner == null) 
     { 
      owner = Window.GetWindow(view); 
     } 

     // Make sure owner window was found 
     if (owner == null) 
     { 
      throw new InvalidOperationException("View is not contained within a Window."); 
     } 

     return owner; 
     } 
+0

こんにちは@Anirban、http://www.codeproject.com/Articles/332615/WPF-Master-Details-MVVM-Applicationからこの記事を追跡し、どのようにモーダルダイアログ作品に見えます。私はこの記事を使って自分のアプリケーションを作成しました。お役に立てれば! –

+0

アプローチは私が提供したリンクと同じです。 –

+0

解決方法はありますか? – Marc

答えて

4

私は右のあなたを取得する場合[OK]を、あなたはないMainWindowViewModelから、異なるChildViewModelからモーダルダイアログを開くようにしたいですか?

は、あなたがリンクされているCodeProjectの記事のMainWindowViewModelのコンストラクタを見てください:

ViewModelには、次のシグネチャを持つコンストラクタを持っています

public MainWindowViewModel(
      IDialogService dialogService, 
      IPersonService personService, 
      Func<IOpenFileDialog> openFileDialogFactory) 

これは、建設のために必要なことを意味しモーダルダイアログを表示するサービス、ここでは関係のない別のサービス(personService)、ファイルを開くための特定のダイアログ(openFileDialogFactory)のファクトリです。

:ViewModelには、必要なサービスのインスタンスを取得するためのServiceLocatorを使用して定義されているシンプルなのServiceLocatorは実装されている記事、およびデフォルトコンストラクタのコア部分であるサービスを、利用するためには

public MainWindowViewModel() 
      : this(
      ServiceLocator.Resolve<IDialogService>(), 
      ServiceLocator.Resolve<IPersonService>(), 
      () => ServiceLocator.Resolve<IOpenFileDialog>()) 
     {} 

ServiceLocatorは静的なので、これは可能です。また、ServiceLocatorを使用して、コンストラクタ内のサービスのローカルフィールドを設定することもできます。 ServiceLocatorを使用したくない場合は、サービスを自分で設定できるので、上記の方法が優れています。

あなた自身のChildViewModelでまったく同じことができます。

public ChildViewModel(IDialogService dialogService) 
{ 
    _dialogService = dialogService; 
} 

のServiceLocatorから解決サービスインスタンスを持つ上記のコンストラクタ呼び出し、デフォルトコンストラクタ、作成します。

public ChildViewModel() : this(ServiceLocator.Resolve<IDialogService>()) {} 

をそして今、あなたはこのようなあなたのChildViewModelのどこからでもサービスを使用することができます。

_dialogService.ShowDialog<WhateverDialog>(this, vmForDialog); 

ビューの所有者ウィンドウ(ビュー自体ではありません)を検索するには、DialogSerのFindOwnerWindowメソッドを変更する必要がありますウィンドウをビュー自体として期待するのではなく、ビューの親ウィンドウを見つけることができます。あなたはそうするVisualTreeHelperを使用することができます。

private Window FindOwnerWindow(object viewModel) 
    { 
     var view = views.SingleOrDefault(v => ReferenceEquals(v.DataContext, viewModel)); 

     if (view == null) 
     { 
      throw new ArgumentException("Viewmodel is not referenced by any registered View."); 
     } 

     DependencyObject owner = view; 

     // Iterate through parents until a window is found, 
     // if the view is not a window itself 
     while (!(owner is Window)) 
     { 
      owner = VisualTreeHelper.GetParent(owner); 
      if (owner == null) 
       throw new Exception("No window found owning the view."); 
     } 

     // Make sure owner window was found 
     if (owner == null) 
     { 
      throw new InvalidOperationException("View is not contained within a Window."); 
     } 

     return (Window) owner; 
    } 

は、あなたはまだユーザーコントロールに添付プロパティを設定すること、しかし、ユーザーコントロールを登録する必要があります。

<UserControl x:Class="ChildView" 
      ... 
      Service:DialogService.IsRegisteredView="True"> 
    ... 
</UserControl> 

は、私の知る限り、これは動作します。

追加情報:

同じことを達成するために、私はPRISMのデカップリングのまさにこの種の多くの機能が付属していますフレームワーク、コントロール(IOC)の反転と依存性注入(DIを使用)。たぶんあなたのためにそれを見る価値があります。

希望すると便利です。

コメントを考慮して編集されました。

+0

問題は、子viewModelが、MainWindoViewModelのようなウィンドウの代わりにユーザーコントロールに対応するという事実にあります。 _dialogService.ShowDialog (これ、vmForDialog).. dialogServiceが "this"のようなdataContextを持つWindowを見つけようとすると失敗します。 DialogService実装のFindOwnerWindowメソッドを見てください。 –

+0

私はこの問題を解決したいと思う。私のアプリケーションでは、任意のユーザーコントロールの対応するビューモデルは、DataContextとしてではなく、ユーザーコントロールのコンテンツとしてユーザーコントロールに関連付けられています。だから私はFindOwnerWindowメソッドを変更する必要があった。編集した投稿を見てください。 –

0

私はCastle WindsorとPrismを使用していますので、あなたの走行距離は変わるかもしれませんが、コンセプトは別のMVVMとIoCと同じにする必要があります。

あなたはモーダルダイアログ

var view = ServiceLocator.Current.GetInstance<SomeDialogView>(); 
view.ShowDialog(); 

もちろん、あなたがDRAT MainView.xaml

に設定したもの
WindowStartupLocation="CenterOwner" 

を尊重いないを開くために望んでいるあなたのMainViewModel.csで始まります!

しかし、ServiceLocatorは私にMainViewを渡すことができませんでしたか?私のIoCは、「過渡的寿命」を持つようにビューを登録するので

var view = ServiceLocator.Current.GetInstance<SomeDialogView>(); 
view.Owner = ServiceLocator.Current.GetInstance<MainView>(); // sure, why not? 
view.ShowDialog(); 

この行は、私のIoCの設定で例外がスローされます。 Castle Windsorでは、各リクエストに新しいインスタンスが用意されており、 MainViewインスタンス自体は表示されていますが、表示されていない新しいインスタンスではありません。

しかし、単にもう少し差別がない限り()流暢を使用して、および(場合であることを、すべてのビューが「一過性」

container.Register(Classes.FromAssemblyNamed("WhateverAssemblyTheyreIn") 
    .InNamespace("WhateverNamespaceTheyreIn") 
    .LifestyleTransient()); 

されてからの登録を変更することによって)

container.Register(Classes.FromAssemblyNamed("WhateverAssemblyTheyreIn") 
    .InNamespace("WhateverNamespaceTheyreIn") 
    .Unless(type => type == typeof(MainView)) 
    .LifestyleTransient()); // all as before but MainView. 

container.Register(Classes.FromAssemblyNamed("WhateverAssemblyTheyreIn") 
    .InNamespace("WhateverNamespaceTheyreIn") 
    .If(type => type == typeof(MainView)) 
    .LifestyleSingleton()); // set MainView to singleton! 

提供MAINVIEW です。

HTH

関連する問題