WPF初心者ですがWindowクラスにイベントを追加したクラスを継承して使いたいです

# 動機

WPFではWindows.Formと違い、DPIが変更されたことやウィンドウの移動、リサイズなどを知る方法がない。つまり自分でウィンドウプロシージャを書かないといけない。しかもウィンドウプロシージャに全部書きだすとそれどこのC言語？となるのでもちろんC#使いが所持する**基本的人権**の一つ`event`を使いたい。つまり`event`実装コードも書く必要がある。

ここでMVVMパターンにおけるViewにあたる`Window`クラスを継承する`partial`クラスにそんな処理をごちゃごちゃ書きたくない、でもWindowクラスの幾つかのイベントをホックしないといけない・・・

これは別クラスに押し込めてViewはそのクラスを継承するべきでは、と思った。

# 書いた

省略するとまず`System.Windows`名前空間に`Window`クラスが多分こんな感じである。

```csharp:Window
namespace System.Windows
{
    public class Window : ContentControl, IWindowService {
        //なんか
    }
}
```

そしてウィンドウプロシージャやらイベントやらを実装したクラスを作った

```csharp:MoreEventWindow.cs
namespace prime_num_searcher_gui
{
    public class MoreEventWindow : Window
    {
        public event EventHandler ResizeBegin;
        protected virtual void OnResizeBegin(EventArgs e) => ResizeBegin?.Invoke(this, e);
        public event EventHandler ResizeEnd;
        protected virtual void OnResizeEnd(EventArgs e) => ResizeEnd?.Invoke(this, e);
        private IntPtr WndProc(IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam, ref bool handled)
        {
            //略
        }
        //ばっさり省略
        public MoreEventWindow()
        {
            this.ResizeBegin += (object sender, EventArgs e) => { this.isBeingMoved = true; };
            this.ResizeEnd += (object sender, EventArgs e) => { this.isBeingMoved = false; };
            this.Move += (object sender, EventArgs e) =>
            {
                if(true == this.willBeAdjusted && this.IsLocationGood())
                {
                    this.willBeAdjusted = false;
                    this.OnDelayedDpiChanged(new DelayedDpiChangedEventArgs(this.dpiOld, this.wParam_, this.lParam_));
                }
            };
        }
    }
}
```


さてこれを継承させよう。

```csharp:MainWindow.xaml.cs
namespace prime_num_searcher_gui
{
    /// <summary>
    /// MainWindow.xaml の相互作用ロジック
    /// </summary>
    public partial class MainWindow : MoreEventWindow
    {
        public MainWindow()
        {
            this.benchmarkExecuter_ = (Environment.Is64BitOperatingSystem) ? new BenchmarkExecuter("prime_num_searcher_x64.exe") : new BenchmarkExecuter("prime_num_searcher.exe");
            InitializeComponent();
            this.SourceInitialized += (object sender, EventArgs e) =>
            {
                this.hWnd_ = new WindowInteropHelper(this).Handle;
                this.benchmarkResultManager_ = new BenchmarkResultManager(this.hWnd_);
            };
        }
    }
}
```

# 問題発生

MainWindowクラスの中で`System.Windows.Window`内にあるものが一切使えない。なんでや？

# 原因

XAML側でもこのMainWindowクラスを自動生成している。だからこそ`partial`キーワードが`MainWindow`クラスに指定されているわけですね。

で、XAML側の基底クラス指定とC#側の基底クラス指定が一致しないので何もできない状態になっていたんですね。

# 解決策

xaml側の基底クラス指定を変えましょう。

```xml
<Window x:Class="prime_num_searcher_gui.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:prime_num_searcher_gui"
        xmlns:oxy="clr-namespace:OxyPlot.Wpf;assembly=OxyPlot.Wpf"
        mc:Ignorable="d"
        Title="PrimeNumSearchBenchmark"
        Height="408" Width="760" MinHeight="428" MinWidth="408"
        Loaded="Window_Loaded"
        FontFamily="Yu Gothic Medium">
    <!-- 略 -->
</Window>
```

これを

```xml
<local:MoreEventWindow x:Class="prime_num_searcher_gui.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:prime_num_searcher_gui"
        xmlns:oxy="clr-namespace:OxyPlot.Wpf;assembly=OxyPlot.Wpf"
        mc:Ignorable="d"
        Title="PrimeNumSearchBenchmark"
        Height="408" Width="760" MinHeight="428" MinWidth="408"
        Loaded="Window_Loaded"
        FontFamily="Yu Gothic Medium">
    <!-- 略 -->
</local:MoreEventWindow>
```

こうじゃ。

ルートのtagが`Window`になっていてこれこそが`x:Class="prime_num_searcher_gui.MainWindow"`で指定している`prime_num_searcher_gui.MainWindow`クラスの基底クラスが`Window`だと指定していたので、`xmlns:local="clr-namespace:prime_num_searcher_gui"`を指定した上でこれを`local:MoreEventWindow`に置き換えたんですね。

# 感想

原因をググってるときになんかxamlもいじらないととかいうサイトばかり見つけてんなわけね～だろ、こいつらみんな狂ってやがる・・・、とか本気で思ってましたが、メロンパンと黒糖蒸しパンと梨を食べて冷静になったあとで`partial`指定されている意味を考えたらすんなり納得できました。

[WPFでFormの継承(Windowの継承 or 見た目の継承？） - かずきのBlog@hatena](http://blog.okazuki.jp/entry/20091025/1256472760)

に感謝を。

<blockquote class="twitter-tweet" data-lang="ja"><p lang="ja" dir="ltr">yumetodoさんが凄いC#コードを書いていたので2度見しています。なんとコメントしたら良いものか……<a href="https://twitter.com/hashtag/%E8%A6%81%E3%81%99%E3%82%8B%E3%81%AB%E7%A7%81%E3%81%AE%E8%85%95%E3%81%8C%E8%B6%B3%E3%82%8A%E3%81%A6%E3%81%AA%E3%81%84?src=hash&amp;ref_src=twsrc%5Etfw">#要するに私の腕が足りてない</a><a href="https://t.co/msHH0ANBeE">https://t.co/msHH0ANBeE</a></p>&mdash; YSR@デレステP (@YSRKEN) <a href="https://twitter.com/YSRKEN/status/913806475578896384?ref_src=twsrc%5Etfw">2017年9月29日</a></blockquote>
<blockquote class="twitter-tweet" data-lang="ja"><p lang="ja" dir="ltr">WinAPIと格闘している辺りが……</p>&mdash; YSR@デレステP (@YSRKEN) <a href="https://twitter.com/YSRKEN/status/913807468655820802?ref_src=twsrc%5Etfw">2017年9月29日</a></blockquote>
<blockquote class="twitter-tweet" data-lang="ja"><p lang="ja" dir="ltr">どっちといった話ではなく、C#でそんなにWinAPI直叩きしないイメージがあるもので……</p>&mdash; YSR@デレステP (@YSRKEN) <a href="https://twitter.com/YSRKEN/status/913817086400458752?ref_src=twsrc%5Etfw">2017年9月29日</a></blockquote>

ところでなんで私はXAML書きながらウィンドウプロシージャ書いてるんだ・・・？

<blockquote class="twitter-tweet" data-lang="ja"><p lang="ja" dir="ltr">yumetodoさんの出題(？)である「DPIが動的に変化しても自ウィンドウのスクショを撮る方法」についていろいろ考えていますが、簡単ではありませんね……<br>次のコードは「DPIが100％表示なら」正常に動くのですが <a href="https://t.co/8y7Dgko0iU">pic.twitter.com/8y7Dgko0iU</a></p>&mdash; YSR@デレステP (@YSRKEN) <a href="https://twitter.com/YSRKEN/status/913847822851596288?ref_src=twsrc%5Etfw">2017年9月29日</a></blockquote>


# ソースコード

[yumetodo/prime_num_searcher at feat/save_graph_image](https://github.com/yumetodo/prime_num_searcher/tree/feat/save_graph_image)

問題が起きていたのは [`b2679f4`](https://github.com/yumetodo/prime_num_searcher/commit/b2679f4e1ab8138fb0c39c69091c6e4b33f46bce)で、解決したのが[`231cb13`](https://github.com/yumetodo/prime_num_searcher/commit/231cb133661c54b39ab046aeb69d821a7897f77d)です。