メインメニューを開く

MVVMモデル

2020年2月6日 (木) 13:28時点におけるRin-scrooge (トーク | 投稿記録)による版
(差分) ← 古い版 | 最新版 (差分) | 新しい版 → (差分)

WPFでアプリ作るたびに調べなおしているので、簡単に上げておきます。
できるだけ簡単に説明するために、WPFのプロジェクトを作成したときにデフォルトで作成される「MainWindow」をMVVM化していきます。

プロジェクトの作成

基本的に、「WPFアプリ(.NET Framework)」または「WPF App(.NET Core)」のどちらかで作成します。

ビュー

デフォルトで作成される「MainWindow.xaml」がビューを定義するファイルとなります。
こんな感じの中身になっているかと思います。


MainWindow.xaml
<Window x:Class="MVVM_Sample.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:MVVM_Sample"
        mc:Ignorable="d"
        Title="MainWindow" Height="450" Width="800">
    <Grid>
        
    </Grid>
</Window>


これをベースに、テキストボックスとボタンを追加して、ボタンを押すとテキストの内容が書き換わるようなものを作ってみます。
以下の様に修正して、テキストボックスとボタンを追加します。


MainWindow.xaml
<Window x:Class="MVVM_Sample.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:MVVM_Sample"
        mc:Ignorable="d"
        Title="MainWindow" Height="450" Width="800 Loaded="MainWindow_Loaded"">
    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition Height="24"/>
            <RowDefinition Height="5"/>
            <RowDefinition Height="24"/>
            <RowDefinition/>
        </Grid.RowDefinitions>
        <TextBlock Grid.Row="0" Text="{Binding ViewText}"/>
        <Button Grid.Row="2" Width="74" HorizontalAlignment="Right" Content="変更" Click="ButtonClick"/>
    </Grid>
</Window>



ポイントは「TextBlock」タグの「Text」属性です。
文字列を表示したい場合はここに文字列を設定しますが、今回はビューモデルを介してやり取りしたいので「Binding ViewText」と設定しています。
これにより、ビューモデル側から「ViewText」プロパティで値を操作できるようになります。

ビューモデル

デフォルトでは作成されないので、適当な名前でクラスファイルを作成します。
今回は「MainWindow_VM.cs」と言う名前で作成していきます。
追加はソリューションエクスプローラーからプロジェクトを右クリックし、「追加」→「クラス」→「ファイル名入力」で追加することができます。
追加されると以下の様な中身になっているかと思います。


MainWindow_VM.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace MVVM_Sample
{
    class MainWindow_VM
    {
    }
}



こいつをビューモデルで使用できるように改造していきます。 ポイントは…

  • 「System.ComponentModel」の参照を追加
  • 「INotifyPropertyChanged」インタフェースを実装
  • 「PropertyChangedEventHandler」イベントハンドラを実装
  • ビューの値を保持できるように、メンバ変数を追加
  • ビューとやり取りする用の、プロパティを追加

です。

それでは改造していきます。


MainWindow_VM.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.ComponentModel; //追加

namespace MVVM_Sample
{
    public class MainWindow_VM : INotifyPropertyChanged //インターフェースを実装
    {
        /// <summary>
        /// イベントハンドラを追加
        /// </summary>
        public event PropertyChangedEventHandler PropertyChanged;

        /// <summary>
        /// ビューの値を保持するためのメンバ変数
        /// </summary>
        private string m_ViewText;

        /// <summary>
        /// デフォルトコンストラクタ
        /// </summary>
        public MainWindow_VM()
        {
            ViewText = "変更前!"; //初期値を設定
        }

        /// <summary>
        /// ビューとやり取りするためのプロパティ
        /// </summary>
        public string ViewText
        {
            get { return m_ViewText; }
            set
            {
                m_ViewText = value;
                OnPropertyChanged("ViewText"); //イベント発動
            }
        }

        /// <summary>
        /// プロパティ変更イベントハンドラ
        /// </summary>
        /// <param name="p_PropertyName">プロパティ名</param>
        public void OnPropertyChanged(String p_PropertyName)
        {
            PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(p_PropertyName));
        }
    }
}


詳細は省略しますが…こんな感じです。

モデル

モデルも、デフォルトで追加されます…が、ボタンをクリックした時の処理が未だ入っていません…。
初期状態でこんな感じになっているかと思います。


MainWindow.xaml.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;

namespace MVVM_Sample
{
    /// <summary>
    /// MainWindow.xaml の相互作用ロジック
    /// </summary>
    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();
        }
    }
}



ポイントは…

  • LaodedイベントハンドラおよびClickイベントハンドラの追加
  • Laodedイベントハンドラでdatacontextの設定
  • Clickイベントハンドラでテキストの文字列の変更処理を追加

です…。

これをするとこんな感じになるかと思います。


MainWindow.xaml.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;

namespace MVVM_Sample
{
    /// <summary>
    /// MainWindow.xaml の相互作用ロジック
    /// </summary>
    public partial class MainWindow : Window
    {
        private MainWindow_VM m_MainWindow_VM;

        public MainWindow()
        {
            InitializeComponent();
        }

        private void MainWindow_Loaded(object sender, RoutedEventArgs e)
        {
            m_MainWindow_VM = new MainWindow_VM();
            DataContext = m_MainWindow_VM;
        }

        private void ButtonClick(object sender, RoutedEventArgs e)
        {
            m_MainWindow_VM.ViewText = "変更!!!!";

            //試しに値をとってみる
            MessageBox.Show(m_MainWindow_VM.ViewText);
        }
    }
}



あとは、コンパイルして動かすだけです。
ボタンを押すと、テキストボックスの文字列が変わって、メッセージボックスが表示されるかと思います。