LoginSignup
1
2

More than 1 year has passed since last update.

ViewからViewModelを閉じたい

Posted at

前提

  • MVVMについての知識。
  • PrismLibraryについての知識。 (BindableBaseが分かれば…)

背景

デスクトップアプリケーションにおいて複数のウィンドウを開いたり閉じたりする要請がよくある。

問題

MVVMを前提とした複数のウィンドウを扱うようなWPFアプリケーションでは、ViewModelがViewを参照した状態でCloseすることは禁忌である。

例えば Sample.csSampleViewModel.cs があったとして、以下のようにViewModelからViewの参照を持ち、そこからClose()メソッドを叩くのはだめ。

// ダメな例
// SampleViewModel.cs
public class SampleViewModel : BindableBase {
    private Sample view;

    public MainWindowViewModel(Sample view) {
        this.view = view;
    }

    public void CloseWindow() {
        view.Close();
    }
}

方法

考え方のフローは1から5までをたどっていく。

  1. ViewからViewModelへ委譲するためのAction型のプロパティをViewModelに用意する必要がある。
  2. 委譲するためのインターフェースを用意する。
  3. ViewModelにインターフェースを持つ。
  4. ViewでViewModelの持つインターフェースのプロパティにメソッドを登録。
  5. ViewModelでコール。

実際に用意する必要があるのは、ViewとViewModelを仲介するインターフェースである。今回の例では、IClosedWindowと名付けることにする。

// IClosedWindow.cs
interface IClosedWindow {
    Action Close { get; set; }
}

次に、このインターフェース(IClosedWindow)をViewModelに実装する。

// SampleViewModel.cs
public class SampleViewModel : BindableBase, IClosedWindow {
    public SampleViewModel {}

    public Action Close { get; set; }

    private DelegateCommand closeCommand;
    public DelegateCommand CloseCommand =>
        closeCommand ??= new DelegateCommand(ExecuteCloseCommand);

    private void ExecuteCloseCommand() {
        Close?.Invoke();
    }
}

そして、ViewはSampleの継承元であるWindowクラスの持つLoadedイベントが発火されたタイミングでDataContextプロパティに登録されたViewModelを参照し、IClosedWindowにキャストする。

// Sample.xaml.cs
public partial class Sample : Window {
    public Sample {
        InitializeComponent();
        Loaded += SampleLoaded;
    }

    private void SampleLoaded(object sender, RoutedEventArgs e) {
        // vmがインターフェースを持っていない場合の処理
        if (DataContext is not IClosedWindow vm)
            return;

        // ここで、Viewを閉じる処理の委譲
        vm.Close += () => {
            this.Close();
        };
    }
}

キャストされたvmClose()に委譲することによって、ViewModel側でコマンドを呼ぶとViewが閉じる。

参考

How to Close Windows from a ViewModel in C#

1
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
2