はじめに
WindowsフォームアプリからWPFアプリに移行すると
MVVMの呪縛にかかり、コードビハインドに何も書けなくなる (※ 個人差があります)
たとえば、フォーム(WPFではウィンドウ)を読み込んだ直後に何かの初期化処理をしたい場合など・・
フォームアプリでは、フォームをダブルクリックすると自動的にForm_Load()メソッドが作られるので、そこに処理を書けばよい
一方、WPFアプリでは・・・Windowをいくら高速クリックしてもメソッドは生成されない😣 
これは困ったことなので、どうしたらいいかを書く
目次のようなもの
<< ゴール >>
WPFアプリにおいて、ウィンドウが読み込まれた直後になんらかの初期化メソッドを呼ぶ
(ただし、コードビハインドには何も追記しない)
流れとしては、まずフォームアプリで所望の動作をさせてみる。
そのあと、WPFアプリで同じことをする
フォームアプリ
おなじみのWindowsフォームアプリ
プロジェクトを立ち上げ直後は、まっさらなフォームが表示される
フォームの上でマウスを左ダブルクリックすると、メソッドが生成される
// フォームをダブルクリックすると、このメソッドが生成される
private void Form1_Load(object sender, EventArgs e)
{
    // フォームをロードし終えたときの動作
}
あとはこの関数の中に、初期化などの処理を書けばいい
フォームアプリについては以上
WPFアプリ
つづいてWPFアプリの2パターン
コードビハインドを使う場合と、使わない場合
Case1: MVVMの呪縛に囚われていない場合
WindowタグにLoaded="Window_Loaded"を追加する
XAMLファイル
 <Window x:Class="MyWpfApp.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:MyWpfApp"
         mc:Ignorable="d"
         Title="MainWindow" Height="450" Width="800"
+        Loaded="Window_Loaded">
     <Grid>
     </Grid>
 </Window>
コードビハインドに同名のメソッドを追加し、中身を書けば終わり
コードビハインド
 public partial class MainWindow : Window
 {
     public MainWindow()
     {
         InitializeComponent();
     }
+    private void Window_Loaded(object sender, RoutedEventArgs e)
+    {
+        // ここに処理を書く
+    }
 }
Tips) IDEの補助機能を有効につかう
ViewでLoaded="まで入力すると、「新しいイベントハンドラー」ポップアップが表示される
このポップアップをクリックすると、コードビハインドにメソッドが自動で追加される
おまけ)ほかのイベントについて
ウィンドウのプロパティを開いて右上の⚡を押せば、使えるであろうたくさんのイベントが表示される
Case2: MVVMの呪縛でコードビハインドに何も書けない場合(本題)
MVVMに従う場合、何はともあれViewModelのファイルを作成する
今回はMainWindowViewModel.csをプロジェクトに追加するものとする
NuGetで必要なライブラリをインストールする
Xaml.Behaviors.Wpfをインストールする
これはViewのイベントとViewModelに定義したコマンドを紐づけるためにつかう
詳しくは・・・System.Windows.Interactivity.dll から Xaml.Behaviors.Wpf へ
ReactivePropertyをインストールする
これはコマンドを簡単に書くためのライブラリである
View (XAML) を編集する
さきほどのLoaded=...イベントは削除する。
代わりにiに関わるものを追加する。
新たに追加した行を見ると
イベントトリガーという名前からして、なにかのイベントに連動して処理が行われそうだとわかる
Loadedと書かれており、きっとウィンドウがロードされたイベントを指定していそうだとわかる
Command="{Binding ...}"でViewModelのコマンドに連動しそうだとわかる
MainWindow.xaml
 <Window x:Class="MyWpfApp.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:MyWpfApp"
+        xmlns:i="http://schemas.microsoft.com/xaml/behaviors"
         mc:Ignorable="d"
         Title="MainWindow" Height="450" Width="800"
-        Loaded="Window_Loaded">
+     <i:Interaction.Triggers>
+         <i:EventTrigger EventName="Loaded">
+             <i:InvokeCommandAction Command="{Binding Loaded_Command}"/>
+         </i:EventTrigger>
+     </i:Interaction.Triggers>
     <Grid>
     </Grid>
 </Window>
ViewModelを編集する
ViewModelはINotifyPropertyChangedを実装する
なぜ必要か? --->>> Q. あれ、ReactivePropertyだとINotifyPropertyChanged要らないんじゃなかったっけ?
ReactiveCommandクラスのLoaded_CommandがViewにバインドされる
.Subscribeの引数(ラムダ式)に書かれた処理が実行される
MainWindowViewModel.cs
using Reactive.Bindings;
using System.ComponentModel;
namespace MyWpfApp
{
    public class MainWindowViewModel : INotifyPropertyChanged
    {
        // Viewにバインドするコマンド
        public ReactiveCommand Loaded_Command { get; } = new();
        public MainWindowViewModel() // コンストラクター内で
        {
            // ボタンが押された時の動作を定義する
            Loaded_Command.Subscribe(()=> System.Diagnostics.Debug.WriteLine("Loaded !!"));
        }
        // これはひとまず気にしないでいい
        public event PropertyChangedEventHandler PropertyChanged;
    }
}
このまま実行しても"Loaded !!"とは表示されない
最後にもう1度、View (XAML) を編集する
ViewとViewModelをつなぐために、Viewを編集する
DataContextにMainWindowViewModelを指定する
MainWindow.xaml
 <Window x:Class="MyWpfApp.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:MyWpfApp"
         xmlns:i="http://schemas.microsoft.com/xaml/behaviors"
         mc:Ignorable="d"
         Title="MainWindow" Height="450" Width="800">
+    <Window.DataContext>
+        <local:MainWindowViewModel/>
+    </Window.DataContext>
     <i:Interaction.Triggers>
         <i:EventTrigger EventName="Loaded">
             <i:InvokeCommandAction Command="{Binding Loaded_Command}"/>
         </i:EventTrigger>
     </i:Interaction.Triggers>
     <Grid>
     </Grid>
 </Window>
なお、MVVMの呪縛に囚われていない場合は
コードビハインドでthis.DataContext = new MainViewModel();としてもよい。
まとめ
ことLoadedイベントだけに関してみれば、WinFormのほうが何も考えずにできてよいかもしれない
しかし、ひるがえってみれば、LoadedのためだけにNuGetを通してわざわざ2つのライブラリをインストールするWPFに対しては、なにかこの先大きなことをしてくれるのではないかと期待してしまう
というまとめ。
                       
                           
                       
                     ↧