MFCでもWinRTその4.　MFCアプリからWinRTコントロールの表示（Buttonのイベントハンドラ追加）

#1. 今回やること
・前回UWPのButtonを表示させましたが、そのイベントハンドラを追加します。
・前回参考にした[MFC に XAML Islands で UWP のコントロールを追加してみよう](https://blog.okazuki.jp/entry/2019/11/01/171855)には書いてあります。しかし、内緒にしといて下さい。

#2. どうやってイベントハンドラを追加するか？
・さて、イベントハンドラを追加しようとMSの[C++ デスクトップ (Win32) アプリで標準 WinRT XAML コントロールをホストする](https://docs.microsoft.com/ja-jp/windows/apps/desktop/modernize/host-standard-control-with-xaml-islands-cpp)を眺めても書いてありません。
・これは困った！どうしよう！ということでXAML islandsのサンプルページを眺めてみます。
・[SampleApp.cpp](https://github.com/microsoft/Xaml-Islands-Samples/blob/master/Samples/Win32/SampleCppApp/SampleApp.cpp)の93行目に

```CPP:SampleApp.cpp（一部抜粋）

 m_buttonClickRevoker = m_xamlButton.Click(winrt::auto_revoke, { this, &AppWindow::OnXamlButtonClick });

```

・とあるので、m_buttonClickRevokerにクリックしたときのイベントハンドラ（AppWindow::OnXamlButtonClick）を登録してそうだと言うのがわかります。

・m_buttonClickRevokerとは何だろうと探して行くと179行目に

```CPP:SampleApp.cpp（一部抜粋）

 winrt::Windows::UI::Xaml::Controls::Button::Click_revoker m_buttonClickRevoker;

```

・とあるので、Click_revokerにイベントハンドラを登録すれば良さそうだなということがわかります。

・イベントハンドラはどんな関数だろうと166行周辺を確認すると、

```CPP:SampleApp.cpp（一部抜粋）

    void OnXamlButtonClick(winrt::Windows::Foundation::IInspectable const& sender, winrt::Windows::UI::Xaml::RoutedEventArgs const&)
    {
        m_mainUserControl.MyProperty(winrt::hstring(L"Xaml K Button 1"));
    }

```

・という関数なので、UWPで追加してくれるいつものイベントハンドラの形で追加すれば良さそうです。

・それではやり方がわかったところで実装しましょう。

#3. イベントハンドラの実装
・まずはMFCWinRTButtonView.hへRevokerとイベントハンドラを登録します。面倒なので両方ともprivate！ついでにイベントハンドラの定義も追加しておいて下さい。

```CPP:MFCWinRTButtonView.h（一部抜粋）

// 生成された、メッセージ割り当て関数
protected:
	afx_msg void OnFilePrintPreview();
	afx_msg void OnRButtonUp(UINT nFlags, CPoint point);
	afx_msg void OnContextMenu(CWnd* pWnd, CPoint point);
	DECLARE_MESSAGE_MAP()
public:
	afx_msg int OnCreate(LPCREATESTRUCT lpCreateStruct);

private:

	//Revokerとイベントハンドラの追加
	winrt::Windows::UI::Xaml::Controls::Button::Click_revoker buttonRevoker;
	void OnXamlButtonClick(winrt::Windows::Foundation::IInspectable const& sender, winrt::Windows::UI::Xaml::RoutedEventArgs const&);

```

・MFCWinRTButtonView.cppのOnCreate()へイベントハンドラを追加します（コントロールを追加した後に？）。

```CPP:MFCWinRTButtonView.cpp（変更後）

int CMFCWinRTButtonView::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
	if (CView::OnCreate(lpCreateStruct) == -1)
		return -1;

	// ハンドルを取得
	auto interop = desktopSource.as<IDesktopWindowXamlSourceNative>();

	// ウインドウへアタッチ
	winrt::check_hresult(interop->AttachToWindow(this->m_hWnd));

	//XAML用のHWNDを取得
	HWND hWndXamlIsland = nullptr;
	interop->get_WindowHandle(&hWndXamlIsland);

	//ボタンの作成
	winrt::Windows::UI::Xaml::Controls::Button button;
	button.Content(winrt::box_value(winrt::hstring(L"Button")));

	//XAML contentの作成。ここにコントロールを追加して行きます
	winrt::Windows::UI::Xaml::Controls::StackPanel xamlContainer;

	//StackPanelへコントロール（ボタン）を登録して、StackPanelをXamlSourceへ追加
	xamlContainer.Children().Append(button);
	desktopSource.Content(xamlContainer);

	//イベントハンドラの登録
	buttonRevoker = button.Click(winrt::auto_revoke, { this, &CMFCWinRTButtonView::OnXamlButtonClick });

	//今回はウインドウの(0,0)～(500,500)の正方形の領域にXAMLを表示しています。
	//画面全体に表示させたい場合はGetWindowRectでウインドウの大きさを取得して,それを指定してください。
	//サイズ変更に対応する場合は、OnSize()を追加して、ハンドルを取得して、StackPanelの大きさを指定してください。
	::SetWindowPos(hWndXamlIsland, NULL, 0, 0, 500, 500, SWP_SHOWWINDOW);
	xamlContainer.UpdateLayout();

	return 0;
}

```

・OnXamlButtonClick()にコードを追加して終了です。今回はダイアログを出すだけです。

```CPP:MFCWinRTButtonView.cpp（変更後）

void CMFCWinRTButtonView::OnXamlButtonClick(winrt::Windows::Foundation::IInspectable const& sender, winrt::Windows::UI::Xaml::RoutedEventArgs const&)
{
	auto msgdlg = winrt::Windows::UI::Popups::MessageDialog(L"Button Click!!");
	msgdlg.as<IInitializeWithWindow>()->Initialize(m_hWnd);
	msgdlg.Content(L"Button Click!!");
	msgdlg.ShowAsync();
}

```

・実行するとこんな感じです。
![10.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/131051/d84c1ada-0bab-0b74-a63e-68a5e4ff619c.png)


#4. 最後に
・MFCでもこんなに簡単にモダン！な感じにできるんです。
・イベントハンドラには今回Click_revokerしか登録しなかったですが、TextBoxにはGettingFocus_revoker等他にも色々あるので試してみて下さい。
・そういえばMicrosoft.Toolkit.Win32.UI.SDKのNugetを追加しなかったけど、無事に動いているなぁ。もし動かなかったら追加してみて下さい。
・次はもう少し違うコントロールを使ってみようかなぁ・・・

[github](https://github.com/yoshiyoshi-git/MFCWinRTButton)はこちら

[目次](https://qiita.com/lilac0011/items/f53f7401ea7da31e3a0b)へ