4-1-2. 実装しよう（①～②まで）

# 1. まずは新規作成
・Visual Studio 2022の「新しいプロジェクトの作成」→「空のアプリ、パッケージ化（デスクトップのWinUI 3）」を選んで新規作成してください。
![1-1 - コピー.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/131051/827de2c2-597e-7cca-af6c-96b9e13c498c.png)

・名前は「PicViewer」としておきます。


# 2. ①インストールしなくても、起動できるようにする。
## 2-1. 「.vcxproj」を編集しよう
・基本的には[MSのページ](https://learn.microsoft.com/ja-jp/windows/apps/winui/winui3/create-your-first-winui3-app#unpackaged-create-a-new-project-for-an-unpackaged-c-or-c-winui-3-desktop-app)の7と8に書かれていることをやります。

・一度VS2022を終了し、「.vcxproj」を適当なテキストエディタで開きます。今回は「PicViewer.vcxproj」をメモ帳で開きます。

・「＜PropertyGroup Label="Globals"＞」タグを探してください。その中からさらに＜AppxPackage＞タグを探してください。その値は最初「true」になっているので「false」へ変更し、その上に「＜WindowsPackageType＞None＜／WindowsPackageType＞を追加します。以下に画像で

変更前
![2-10.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/131051/e1572ac2-e703-479b-f7f0-36221be1d123.png)

変更後
![2-11.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/131051/2cbd8413-09c1-18e8-5da4-620e268496e0.png)

<br>

・ここまで出来たら、一旦念のためリリースモードでビルドし実行してください。
・x64\Releaseの中にある「PicViewer」フォルダを適当なフォルダへコピーし、以下の3ファイル以外はすべて削除。それでも実行できるはずです。
　●Microsoft.WindowsAppRuntime.Bootstrap.dll
　●PicViewer.exe
　●resources.pri
・つまり、この3ファイルさえあればどこに置いても実行可能となります（別のライブラリ等が必要な場合は除く）
・これで①は終了です。後はいらないボタンとプロパティを削除します。


## 2-2. 一度WinUI3とC++／WinRTの違いを見てみよう。
### 2-2-1. ファイル構成
・大きなところではC++／WinRTは「MainPage.xaml」だったものが、WinUI3では「MainWindow.xaml」へ変更になっています。
・C++／WinRT
![2-20.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/131051/5e2da61e-ce11-8ff6-2f01-d121a3bdfdf2.png)

・WinUI3
![2-21.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/131051/c8d0ac77-185c-e4b9-e61d-1659376da3c2.png)

### 2-2-2. Main.cpp
・UIへアクセスするnamespaceがC++／WinRTは「winrt::Windows～」だったものが、WinUI3では「winrt::Microsoft～」へ変更になっています。違うところでも書いた気がするけど「Microsoft::～」というnamespaceのライブラリもあるので、それらを使用するときはバッティングしてコンパイルエラーとなります。
・そのときは「using namespace winrt;」を削除して「winrt::Microsoft::～」で書いてください。そんなアホなことにならないようにnamespaceがあるはずなんだけどorz
・UI関連以外は「winrt::Windows～」のnamespaceにあるものが多く、UIに渡すときに間違えて「Windows～」のまま渡してコンパイルエラーとなるときもあるのでかなり鬱陶しいです。~~もっとちゃんと作らないとますます使われ無くなるぞMS！~~


```CPP:MainPage.cpp（C++／WinRT）
#include "pch.h"
#include "MainPage.h"
#include "MainPage.g.cpp"

using namespace winrt;
using namespace Windows::UI::Xaml;

namespace winrt::Test0001::implementation
{
}

```

```CPP:MainWindow.xaml.cpp（WinUI3）
#include "pch.h"
#include "MainWindow.xaml.h"
#if __has_include("MainWindow.g.cpp")
#include "MainWindow.g.cpp"
#endif

using namespace winrt;
using namespace Microsoft::UI::Xaml;


namespace winrt::PicViewer::implementation
{
}


```



# 3. ②メニューから「File→Exit」でアプリを終了するか聞いてくるダイアログを表示する。

## 3-1 メニューバーを配置
・メニューバーをどうやって配置するのか、[WinUI 3 Gallery](https://apps.microsoft.com/detail/9p3jfpwwdzrc?hl=ja-JP&gl=JP)を見て確認してみます（UI関連は参考になるのでwinui3.0を使うのならインストールした方が良いですよ）。
![2-22.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/131051/69761a02-eb9b-6ddb-b2e9-5f26b149b69f.png)
見た感じそんなに難しくなさそうなので、さっくりMainWindowを変更しましょう。

・メニューを追加して「File→Open」と「File→Exit」も追加しました。
・それぞれ、クリックと「Ctrl+O」と「Ctrl+E」のショートカットも作成しています。
```xml:MainWindow.xaml

<?xml version="1.0" encoding="utf-8"?>
<Window
    x:Class="PicViewer.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="using:PicViewer"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    mc:Ignorable="d">

    <Grid RequestedTheme="Default" >

        <Grid.RowDefinitions>
            <RowDefinition Height="auto" />

        </Grid.RowDefinitions>
        <MenuBar Background="LightGray" BorderBrush="Black" BorderThickness="1" CornerRadius="5">
            <MenuBarItem Title="File">
                
                <MenuFlyoutItem Text="Open" Click="Open_Click">
                    <MenuFlyoutItem.KeyboardAccelerators>
                        <KeyboardAccelerator Modifiers="Control" Key="O"/>
                    </MenuFlyoutItem.KeyboardAccelerators>
                </MenuFlyoutItem>

                <MenuFlyoutItem Text="Exit" Click="Exit_Click">
                    <MenuFlyoutItem.KeyboardAccelerators>
                        <KeyboardAccelerator Modifiers="Control" Key="E"/>
                    </MenuFlyoutItem.KeyboardAccelerators>
                </MenuFlyoutItem>
                
            </MenuBarItem>
        </MenuBar>

        
    </Grid>
</Window>


```
<br>
<br>

・MainWindow.xaml.hは各メンバ関数の定義と、コンストラクタでタイトルを変更します。変更しないと「WinUI Desktop」ってデフォルトのファイル名のままになってしまいますから。
・Open_Clickはまだ中身を追加しないのでvoidのまま、Exit_ClickはIAsyncActionへと変更します。
・[MSのページ](https://learn.microsoft.com/ja-jp/windows/apps/windows-app-sdk/migrate-to-windows-app-sdk/guides/winui3#messagedialog-and-pickers)に書いてありますが、メッセージダイアログやピッカーを使用する場合HWNDを取得する必要があります。このため、getHwnd()も追加しました。

```CPP:MainWindow.xaml.h

#pragma once

#include "MainWindow.g.h"

namespace winrt::PicViewer::implementation
{
    struct MainWindow : MainWindowT<MainWindow>
    {
        MainWindow()
        {
            //タイトル名の変更        
            this->Title(L"PicViewer");
        }

        //HWND取得関数
        HWND getHwnd();

        //Openがクリックされたよ！
        void Open_Click(winrt::Windows::Foundation::IInspectable const& sender, winrt::Microsoft::UI::Xaml::RoutedEventArgs const& e);
        
        //Exitがクリックされたよ！ -ここは非同期へ変更       
        winrt::Windows::Foundation::IAsyncAction Exit_Click(winrt::Windows::Foundation::IInspectable const& sender, winrt::Microsoft::UI::Xaml::RoutedEventArgs const& e);
    };
}

namespace winrt::PicViewer::factory_implementation
{
    struct MainWindow : MainWindowT<MainWindow, implementation::MainWindow>
    {
    };
}

```

<br>
<br>

・mainWindow.xaml.cppでgetHwndとExit_Clickの実装を行います。Exitをクリックすると「Yes」「No」「Cancel」の三つのボタンを表示するContentDialogを表示します。
・「Yes」はそのままアプリを終了。
・「No」はMessageDialogを表示して続行。
・「Cancel」は何も表示せず続行。
・各種ダイアログを表示したいだけだったけど、なんでContentDialogとMessageDialogで諸々違うの...

```CPP:MainWindow.xaml.cpp

#include "pch.h"
#include "MainWindow.xaml.h"
#if __has_include("MainWindow.g.cpp")
#include "MainWindow.g.cpp"
#endif

using namespace winrt;
using namespace Microsoft::UI::Xaml;

//::IWindowNativeと::IInitializeWithWindowを使うのにmicrosoft.ui.xaml.window.h、Shobjidl.hが必要
//MessageDialogを使うのにWindows.UI.Popups.hが必要
#include <microsoft.ui.xaml.window.h>
#include <winrt/Windows.UI.Popups.h>
#include <Shobjidl.h>


namespace winrt::PicViewer::implementation
{
	
}



HWND winrt::PicViewer::implementation::MainWindow::getHwnd()
{
	auto windowNative{ this->m_inner.as<::IWindowNative>() };
	HWND hWnd{ 0 };
	windowNative->get_WindowHandle(&hWnd);

	return hWnd;
}

void winrt::PicViewer::implementation::MainWindow::Open_Click(winrt::Windows::Foundation::IInspectable const& sender, winrt::Microsoft::UI::Xaml::RoutedEventArgs const& e)
{
}


winrt::Windows::Foundation::IAsyncAction winrt::PicViewer::implementation::MainWindow::Exit_Click(winrt::Windows::Foundation::IInspectable const& sender, winrt::Microsoft::UI::Xaml::RoutedEventArgs const& e)
{
	//ContentDialogはwinrt::Microsoft...となる。必要なのはXamlRoot
	Microsoft::UI::Xaml::Controls::ContentDialog isenddialog{};
	isenddialog.XamlRoot(this->Content().XamlRoot());
	isenddialog.Title(box_value(L"Do you want to close?"));
	isenddialog.PrimaryButtonText(L"Yes");
	isenddialog.SecondaryButtonText(L"No");
	isenddialog.CloseButtonText(L"Cancel");

	auto result = co_await isenddialog.ShowAsync();
 
	if (result == Microsoft::UI::Xaml::Controls::ContentDialogResult::Primary)
	{
 		//アプリ終了
		Application::Current().Exit();
	}
	else if (result == Microsoft::UI::Xaml::Controls::ContentDialogResult::Secondary)
	{
		//MessageDialogはwinrt::Windows...となる。必要なのはHWND
		auto showdialog{ Windows::UI::Popups::MessageDialog(L"Continue without closing this application") };
		showdialog.as<::IInitializeWithWindow>()->Initialize(getHwnd());

		co_await showdialog.ShowAsync();
	}
}

```

<br>
<br>

・これでメニューの追加、アプリの終了処理まで終了しました。
・実行すると以下のようになります。
![2-23.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/131051/521bea89-3d42-43a8-efe3-1c18fa2c8937.png)

[次へ](https://qiita.com/lilac0011/items/636f62cff1fadaec47a5)

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