0

ViewModel からウィンドウを閉じようとしています。MVVM パターンを使用しています。ウィンドウを使用するのにうんざりしています。

Window parentWindow = Window.GetWindow(this);

しかし、私はこれを行うことはできません.ViewModelのウィンドウを取得するにはどうすればウィンドウを閉じることができますか. これをコードで実行できるようにしたい。

コードで親ウィンドウを見つけることができますか?

4

5 に答える 5

3

ViewModelsViewMVVM では、ウィンドウを閉じるなど、いかなる方法でも を参照しないでください。

代わりに、Viewとの間の通信は通常、 Microsoft PrismMVVM LightViewModelなどのイベントまたはメッセージング システムを通じて行われます。EventAggregatorMessenger

たとえば、Viewはタイプ のイベント メッセージをリッスンするためにサブスクライブする必要がCloseWindowあり、それらのメッセージの 1 つを受信すると、それ自体を閉じる必要があります。次に、は、閉じるように伝えたいときはいつでもメッセージViewModelをブロードキャストする必要があります。CloseWindowView

MVVM のイベント システムの簡単な概要といくつかの例については、ViewModel 間の通信に関する私のブログ投稿 (興味がある場合) を参照してください。

于 2012-06-14T16:46:02.600 に答える
1

はい、viewmodelでビューを参照することはベストプラクティスではありません。なぜ?ビューモデルを単体テストするときは、ビューをインスタンス化する必要があるためです。小さなビューの場合はそれを行うのは難しくありませんが、複雑な依存関係のツリーを持つ複雑なビューの場合はどうでしょうか。それは良くないでしょう。

私にとって、viewと通信する最も簡単な方法は、IInputElementviewmodelコンストラクターを渡すことです。の利点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のようなモックライブラリを使用できます

詳細については、ルーテッドイベントの使用方法について詳しく知ることができます。

于 2012-06-17T01:11:58.277 に答える
0

ViewModel でアクションを定義できます

public Action CloseAction { get; set; }

次に、ウィンドウで (たとえば、DataContextChanged で) このアクションを設定できます。

((IClosable)viewModel.Content).CloseAction = () => System.Windows.Application.Current.Dispatcher.Invoke(Close());

さて、これはすべてより大きな依存性注入パターンの一部ですが、基本原則はここにあります... 次に、VM からアクションを呼び出す必要があります。

于 2012-06-14T15:25:45.330 に答える
0

このタスクには、ViewModel 内で完全に定義されたコマンドに View をフックできるようにする、Expression Blend 3 で導入された動作である MVVM を壊さない便利な動作があります。

この動作は、ViewModel が Model-View-ViewModel アプリケーションで View の終了イベントを管理できるようにする簡単な手法を示しています。

これにより、コントロールのウィンドウを制御するビュー (UserControl) でビヘイビアーをフックすることができ、ViewModel は標準の ICommand を介してウィンドウを閉じることができるかどうかを制御できます。

ViewModel が MV-VM でビューの有効期間を管理できるようにビヘイビアを使用する

http://gallery.expression.microsoft.com/WindowCloseBehavior/

于 2012-06-14T17:58:31.897 に答える
0

本当に必要な場合は、ViewModel にこれを行わせてください。

モデルは、たとえば、有効なデータがなくなったことを示しています

その情報をViewModelに渡します

ViewModel は、もはや何も表示できないことを認識します

ウィンドウを閉じます。

空のビューは、これ以上データがないことを表す通常の方法です

于 2012-06-14T15:14:43.290 に答える