ViewModel からウィンドウを閉じようとしています。MVVM パターンを使用しています。ウィンドウを使用するのにうんざりしています。
Window parentWindow = Window.GetWindow(this);
しかし、私はこれを行うことはできません.ViewModelのウィンドウを取得するにはどうすればウィンドウを閉じることができますか. これをコードで実行できるようにしたい。
コードで親ウィンドウを見つけることができますか?
ViewModels
View
MVVM では、ウィンドウを閉じるなど、いかなる方法でも を参照しないでください。
代わりに、View
との間の通信は通常、 Microsoft PrismやMVVM LightViewModel
などのイベントまたはメッセージング システムを通じて行われます。EventAggregator
Messenger
たとえば、View
はタイプ のイベント メッセージをリッスンするためにサブスクライブする必要がCloseWindow
あり、それらのメッセージの 1 つを受信すると、それ自体を閉じる必要があります。次に、は、閉じるように伝えたいときはいつでもメッセージViewModel
をブロードキャストする必要があります。CloseWindow
View
MVVM のイベント システムの簡単な概要といくつかの例については、ViewModel 間の通信に関する私のブログ投稿 (興味がある場合) を参照してください。
はい、viewmodelでビューを参照することはベストプラクティスではありません。なぜ?ビューモデルを単体テストするときは、ビューをインスタンス化する必要があるためです。小さなビューの場合はそれを行うのは難しくありませんが、複雑な依存関係のツリーを持つ複雑なビューの場合はどうでしょうか。それは良くないでしょう。
私にとって、viewと通信する最も簡単な方法は、IInputElement
viewmodelコンストラクターを渡すことです。の利点IInputElement
はルーティングイベントバックボーンであり、ルーティングイベントに必要なメソッドがRaiseEvent
あります。AddHandler
したがって、追加のライブラリなしで、アプリケーションの任意のビューまたはビューモデルにイベントをバブル/トンネル/ダイレクトすることができます。
これがviewmodelの簡略化されたコードですが、この手法はビューファーストアプローチでのみ機能することを覚えておいてください
public class MyViewModel : INotifyPropertyChanged
{
public static readonly RoutedEvent RequestCloseEvent = EventManager.RegisterRoutedEvent("RequestClose",
RoutingStrategy.Bubble, typeof(RoutedEventHandler), typeof(MyViewModel));
private IInputElement dispatcher;
public MyViewModel(IInputElement dispatcher)
{
this.dispatcher = dispatcher;
}
public void CloseApplication()
{
dispatcher.RaiseEvent(new RoutedEventArgs(RequestCloseEvent));
}
}
単にあなたのビューに
DataContext = new MyViewModel(this)
//notice "this" on the constructor
アプリケーションのルートビュー(ウィンドウ)は単純に
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
AddHandler(MyViewModel.RequestCloseEvent, new RoutedEventHandler(onRequestClose));
}
private void onRequestClose(object sender, RoutedEventArgs e)
{
if (MessageBox.Show("Are you sure you want to quit?", "Confirmation", MessageBoxButton.YesNo) == MessageBoxResult.Yes)
{
Close();
}
}
}
また、IInputElement
はクラスではなくインターフェースであるため、単体テスト用のモッククラスを簡単に作成できます。
var target = new MyViewModel(new DispatcherMock)
または、RhinoMocksのようなモックライブラリを使用できます
詳細については、ルーテッドイベントの使用方法について詳しく知ることができます。
ViewModel でアクションを定義できます
public Action CloseAction { get; set; }
次に、ウィンドウで (たとえば、DataContextChanged で) このアクションを設定できます。
((IClosable)viewModel.Content).CloseAction = () => System.Windows.Application.Current.Dispatcher.Invoke(Close());
さて、これはすべてより大きな依存性注入パターンの一部ですが、基本原則はここにあります... 次に、VM からアクションを呼び出す必要があります。
このタスクには、ViewModel 内で完全に定義されたコマンドに View をフックできるようにする、Expression Blend 3 で導入された動作である MVVM を壊さない便利な動作があります。
この動作は、ViewModel が Model-View-ViewModel アプリケーションで View の終了イベントを管理できるようにする簡単な手法を示しています。
これにより、コントロールのウィンドウを制御するビュー (UserControl) でビヘイビアーをフックすることができ、ViewModel は標準の ICommand を介してウィンドウを閉じることができるかどうかを制御できます。
ViewModel が MV-VM でビューの有効期間を管理できるようにビヘイビアを使用する
http://gallery.expression.microsoft.com/WindowCloseBehavior/
本当に必要な場合は、ViewModel にこれを行わせてください。
モデルは、たとえば、有効なデータがなくなったことを示しています
その情報をViewModelに渡します
ViewModel は、もはや何も表示できないことを認識します
ウィンドウを閉じます。
空のビューは、これ以上データがないことを表す通常の方法です