#1. 今回やること
・前回UWPのButtonを表示させましたが、そのイベントハンドラを追加します。
・前回参考にしたMFC に XAML Islands で UWP のコントロールを追加してみようには書いてあります。しかし、内緒にしといて下さい。
#2. どうやってイベントハンドラを追加するか?
・さて、イベントハンドラを追加しようとMSのC++ デスクトップ (Win32) アプリで標準 WinRT XAML コントロールをホストするを眺めても書いてありません。
・これは困った!どうしよう!ということでXAML islandsのサンプルページを眺めてみます。
・SampleApp.cppの93行目に
m_buttonClickRevoker = m_xamlButton.Click(winrt::auto_revoke, { this, &AppWindow::OnXamlButtonClick });
・とあるので、m_buttonClickRevokerにクリックしたときのイベントハンドラ(AppWindow::OnXamlButtonClick)を登録してそうだと言うのがわかります。
・m_buttonClickRevokerとは何だろうと探して行くと179行目に
winrt::Windows::UI::Xaml::Controls::Button::Click_revoker m_buttonClickRevoker;
・とあるので、Click_revokerにイベントハンドラを登録すれば良さそうだなということがわかります。
・イベントハンドラはどんな関数だろうと166行周辺を確認すると、
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!ついでにイベントハンドラの定義も追加しておいて下さい。
// 生成された、メッセージ割り当て関数
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()へイベントハンドラを追加します(コントロールを追加した後に?)。
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()にコードを追加して終了です。今回はダイアログを出すだけです。
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();
}
#4. 最後に
・MFCでもこんなに簡単にモダン!な感じにできるんです。
・イベントハンドラには今回Click_revokerしか登録しなかったですが、TextBoxにはGettingFocus_revoker等他にも色々あるので試してみて下さい。
・そういえばMicrosoft.Toolkit.Win32.UI.SDKのNugetを追加しなかったけど、無事に動いているなぁ。もし動かなかったら追加してみて下さい。
・次はもう少し違うコントロールを使ってみようかなぁ・・・
githubはこちら
目次へ