2
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

MVVM Show View パターン1 Viewのコードビハインド

Last updated at Posted at 2020-09-24

Viewを表示するパターンを考える

MVVMを勉強しはじめた時に、いったいコードをどうかけばいいのかさっぱり分からなかったのことは、Viewを表示するコードをどこに書くのか?
今でもそれらが曖昧なので、明確にしておくためにこの記事を書きます。
ただし、調べると、より分からない点がさらに増えました。
フィードバックを頂けるとありがたいです。

Newする順序

V・VM・MをNewする順序も、パターンによって異なります。それにも留意します。

結合・参照?

MVVMでは、ModelはViewModelを知らないし、ViewModelはViewを知らない、ことが前提です。
この知らない、というのは、名前を知っているだけなのは知るうちに入るのか入らないのか。この点がよくわかりません。
例えば、SubView.xamlを新しく表示する場合、SubViewという確定している名前がコードに書かれているだけなら、それで知っていることになるのか?ということです。
これについては、パターン2の、Commandパラメータで考えます。

コード

開発環境

.NET Core 3.1 + ReactiveProperty で構築します。

パターン 1 Viewのコードビハインド

アプリを起動した時の最初のViewは、App.xamlのStartupUriで指定します。
それ以降のViewを、Viewのコードビハインドから表示します。

ファイルの構成

Class
Model MainManager
ViewModel MainViewModel
View MainView

Newする順序は、

  1. ViewからViewModelをNew
  2. NewされたViewModelから、ModelをNewします。

V → VM → M の順序です。

プロジェクトの構成

image.png

スタート時のウインドウ

App.xamlの、StartupUriに、MainView.xamlを指定しました。

<Application
    x:Class="ShowView1.App"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="clr-namespace:ShowView1"
    StartupUri="View/MainView.xaml">

MainViewのコードビハインド

MainViewModelをNewしています。
DataContextに、vmをセットします。ここではなく、XAMLでVMを指定もできます。
ただし、ViewのコードビハインドでVMのメソッドを呼び出すことがあるなら、ここで指定しておくと便利だと思います。

  public partial class MainView : Window
    {
        MainViewModel vm = new MainViewModel();
        public MainView()
        {
            InitializeComponent();
            this.DataContext = vm;
        }

ViewModel

ModelをNewして保持します

    class MainViewModel : INotifyPropertyChanged, IDisposable
    {
        public MainManager Model { get; }

        public MainViewModel()
        {
            Model = new MainManager();

ボタンクリックで新しいViewを表示

ボタンをクリックして、別のViewを表示するには、

        private void Button_Click(object sender, RoutedEventArgs e)
        {
            var cls = new MainView();
            cls.Show();
        }

Viewのコードビハインドで良いはずです。
ここでは、2つめのMainViewを表示しています。

Viewと他のViewとの関係

ここでは、ボタンクリックで、MainViewをさらに表示していますが、他のViewを表示するのも同じです。

SubViewがあるとすれば、

  • MainViewのボタンクリック
  • SubViewを表示

になります。
これだと、MainViewは、SubViewを知っていることになります。SubViewという名前を知っているし、参照もしています。MVVMとして、それで良いのかどうかが分かりません。

View1が、View2を、表示する処理(閉じる処理も?)を、View1で行って良いとすると、また、例えば、View2のDialogResultを、View1で受け取り、ViewModel, ViewModel経由でModelで処理をする程度のこともOKかもしれません。

Viewのコードビハインドの是非

Viewには、できるだけコードを書かないでおこうという考え方もあるのですが、私は次の条件の時は、Viewにコードを書くと良いと考えます。

  • Viewに関わる事
  • Viewのコードで処理した方が、ViewModelやModelで処理するより容易

XAMLに書くのも、Viewにコードビハインドで書くのも同じViewでの処理です。単に、言語がXAMLなのかC#なのか程度の違いです。
https://stackoverflow.com/a/37294259/9924249

XAMLだけで処理をしようとして、複雑なコードになるのは本末転倒な気がします。また、UIのテストが行いやすくなるからXAMLだけで処理をしようとするのも、同様に本末転倒に思います。

同様の例

Handle it in the view
https://stackoverflow.com/a/5829704/9924249

private void AddCustomerView_Click(object sender, RoutedEventArgs e)
{
    AddCustomerView view = new AddCustomerView(data);
    view.Show();
}

となっています。ここでは、ViewをNewする時に、引数としてdataを渡していますが、このdataはモデルのデータであるはずです。それを、Viewから渡すことは、MVVMらしいでしょうか? これも分からない点です。

疑問点まとめ

  • Viewが他のViewを知っているのはMVVMとしてそれでよいのか?
  • ViewからViewを表示する場合、引数(Modelのデータ)をどうやって渡すのか?

単純な処理なようで、疑問も増えました。このパターンを基本として、他のパターンと比べていきましょう。

記事予定

2
3
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
2
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?