4-1-3. 実装しよう（③～④まで）

# 4. ③メニューから「File→Open」でフォルダーピッカーを表示し、画像を保存しているフォルダを選べるようにする
・ここはフォルダーピッカーの使い方になります。

・フォルダーピッカーを使用するのでOpen_ClickもIAsyncActionへ変更します。
```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がクリックされたよ！-ここは非同期へ変更
        winrt::Windows::Foundation::IAsyncAction 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>

・次は実装です。こちらは実装するOpen_Clickまで載せます。
・フォルダピッカーで最初に開くフォルダはピクチャフォルダを提案します。
・フォルダーピッカーで「キャンセル」を選ぶとnullptrを返します。そのときはco_returnします。
```CPP:MainWindow.xaml.h

#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>

//FolderPickerを使用するのにwinrt/Windows.Storage.Pickers.hが必要
#include <winrt/Windows.Storage.Pickers.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;
}

winrt::Windows::Foundation::IAsyncAction winrt::PicViewer::implementation::MainWindow::Open_Click(winrt::Windows::Foundation::IInspectable const& sender, winrt::Microsoft::UI::Xaml::RoutedEventArgs const& e)
{
	//各種ピッカーもwinrt::Windows～
	auto folderpicker = Windows::Storage::Pickers::FolderPicker();
	folderpicker.as<::IInitializeWithWindow>()->Initialize(getHwnd());

	//初期に開くフォルダはピクチャフォルダ
	folderpicker.SuggestedStartLocation(Windows::Storage::Pickers::PickerLocationId::PicturesLibrary);

	//ピッカーを表示
	auto&& serchfolder = co_await folderpicker.PickSingleFolderAsync();

	//キャンセルだったらco_return
	if (serchfolder == nullptr)
		co_return;
}

//以下Exit_Click()なので後略

```

・ここまで出来たら、以下の図のようになります。
![4-1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/131051/da401caf-30a7-db28-0dc8-3469fb433c35.png)


# 5. ④フォルダーピッカーで選んだフォルダにある画像のサムネイルを表示する。
・基本的には[C++/WinRTでUWPその13　ピクチャフォルダをサムネイル表示しよう](https://qiita.com/lilac0011/items/4c897212d236df43fee6)とほぼ同じことを行って、メニューバーの下にグリッドビューを配置しそこへフォルダにある画像のサムネイルを表示させます。
・前回と同じように、
　5-1.StorageFile+サムネイル+ファイル名を保存するViewModelを作成
　5-2.ViewModelを取得する部分をOpen_Clickへ追加。IObservableVectorへ保存
　5-3.MenuBarの下へGridViewを配置、②のVectorをBindし表示
 の順に進みます

## 5-1.StorageFile+サムネイル+ファイル名を保存するViewModelを作成
・まずは「thumbViewModel」という名前でViewModelを追加し、諸々追記します。追加するのはビューモデル（C++／WinRT）です。WinUI 3のビューモデルはないので。
![5-1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/131051/772c0446-5f3f-2834-060c-2d714ea48967.png)

<br>

・それでは追記していきます。
・まずはthumbViewModel.idlから。基本的には[その13](https://qiita.com/lilac0011/items/4c897212d236df43fee6)とほぼ同じですが、BitmapImageがWindows.UI～では無く、Microsoft.UI～となります。間違えると後でコンパイルエラーとなります。

```xml:thumbViewModel.idl

namespace PicViewer
{
    [bindable]
    [default_interface]
    runtimeclass thumbViewModel 
    {
        thumbViewModel();
        thumbViewModel(Windows.Storage.StorageFile imagefile, Microsoft.UI.Xaml.Media.Imaging.BitmapImage thunbimage, String imagename);

        Windows.Storage.StorageFile GetImageFile{ get; };
        Microsoft.UI.Xaml.Media.Imaging.BitmapImage GetThumbImage{ get; };
        String GetImageName{ get; };
    }
}

```

<br>

・thumbViewModelの実装はthumbViewModel.hでやってしまいます。
・Windows～とMicrosoft～さえ間違えなければ、[その13](https://qiita.com/lilac0011/items/4c897212d236df43fee6)そのままです。
・thumbViewModel.cppは載せませんが、propertyとかご丁寧に書いてくれているのでそれを削除しておいてください。
```C++:thumbViewModel.h

#pragma once

#include "thumbViewModel.g.h"

namespace winrt::PicViewer::implementation
{
    struct thumbViewModel : thumbViewModelT<thumbViewModel>
    {
        thumbViewModel() = default;

        thumbViewModel(
            //StorageFileはWindows～
            Windows::Storage::StorageFile const& imagefile,
            //BitmapImageはMicrosoft～
            Microsoft::UI::Xaml::Media::Imaging::BitmapImage const& thumbimage,
            hstring const& imagename
        ) :
            _imageFile(imagefile),
            _thumbImage(thumbimage),
            _imageName(imagename)
        {}

        Windows::Storage::StorageFile GetImageFile() const
        {
            return _imageFile;
        }

        Microsoft::UI::Xaml::Media::Imaging::BitmapImage GetThumbImage() const
        {
            return _thumbImage;
        }

        hstring GetImageName() const
        {
            return _imageName;
        }

    private:
        Windows::Storage::StorageFile _imageFile{ nullptr };
        Microsoft::UI::Xaml::Media::Imaging::BitmapImage _thumbImage;
        hstring _imageName;

    };
}

namespace winrt::PicViewer::factory_implementation
{
    struct thumbViewModel : thumbViewModelT<thumbViewModel, implementation::thumbViewModel>
    {
    };
}


```

## 5-2.ViewModelを取得する部分をOpen_Clickへ追加。IObservableVectorへ保存
・まずはMainWindow.idlへthumbViewModelVecを追加。
・次にサムネイル取得関数と、Open_Click関数へthmubViewModel取得部分を追加。
の順で進めます。

<br>

・MainWindow.idlではまず、thumbViewModelをimportし、viewModelVecを追加します。
```xml:MainWindow.idl

import "thumbViewModel.idl";

namespace PicViewer
{
    [default_interface]
    runtimeclass MainWindow : Microsoft.UI.Xaml.Window
    {
        MainWindow();
        Windows.Foundation.Collections.IObservableVector<IInspectable> viewModelVec{ get; };
    }
}


```

<br>

・MainWindow.xaml.hでは、thumbViewModelを保存するメンバの作成および初期化を行い、idlで宣言したゲッターの実装を追加します。
```CPP:MainWindow.xaml.h

#pragma once

#include "MainWindow.g.h"

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

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

        //idlで宣言したゲッター
        Windows::Foundation::Collections::IObservableVector<Windows::Foundation::IInspectable> viewModelVec() const
        {
            return _thumbViewModelVec;
        }

        //Openがクリックされたよ！-ここは非同期へ変更
        winrt::Windows::Foundation::IAsyncAction 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);
    
    private:
        //thumbViewModelを保存するメンバ
        Windows::Foundation::Collections::IObservableVector<Windows::Foundation::IInspectable> _thumbViewModelVec{ nullptr };    
    };
}

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

```

<br>

・MainWindow.xaml.hでは、必要なヘッダをインクルードして、OpenClick関数の後半にthumbViewModelを取得する部分を追加します。
```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>

//FolderPickerを使用するのにwinrt/Windows.Storage.Pickers.hが必要
#include <winrt/Windows.Storage.Pickers.h>

//Windows::Storage::Search～を使用するのに必要
#include <winrt/Windows.Storage.Search.h>

//thumbViewModel.hも忘れずに
#include"thumbViewModel.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;
}

winrt::Windows::Foundation::IAsyncAction winrt::PicViewer::implementation::MainWindow::Open_Click(winrt::Windows::Foundation::IInspectable const& sender, winrt::Microsoft::UI::Xaml::RoutedEventArgs const& e)
{
	//各種ピッカーもwinrt::Windows～
	auto folderpicker = Windows::Storage::Pickers::FolderPicker();
	folderpicker.as<::IInitializeWithWindow>()->Initialize(getHwnd());

	//初期に開くフォルダはピクチャフォルダ
	folderpicker.SuggestedStartLocation(Windows::Storage::Pickers::PickerLocationId::PicturesLibrary);

	//ピッカーを表示
	auto&& serchfolder = co_await folderpicker.PickSingleFolderAsync();

	//キャンセルだったらco_return
	if (serchfolder == nullptr)
		co_return;

	//ここから選択されたフォルダの画像ファイルを変換・保存
	_thumbViewModelVec.Clear();

	//jpgとpngとbmpとgif画像を探す。さがすフォルダはそのフォルダのみ
	Windows::Storage::Search::QueryOptions serchoptions{};
	serchoptions.FileTypeFilter().Append(L".jpg");
	serchoptions.FileTypeFilter().Append(L".png");
	serchoptions.FileTypeFilter().Append(L".bmp");
	serchoptions.FileTypeFilter().Append(L".gif");
	serchoptions.FolderDepth(Windows::Storage::Search::FolderDepth::Shallow);

	//フォルダ内をサーチして、画像ファイルのStorageFileをallimageへ保存
	auto serchresult = serchfolder.as<Windows::Storage::Search::IStorageFolderQueryOperations>().CreateFileQueryWithOptions(serchoptions);
	auto&& allimage = co_await serchresult.GetFilesAsync();

	//allimageをすべて走査して3つすべて取得できれば、_thumbViewModelVecへ保存
	for (auto&& imagefile : allimage)
	{
		auto&& thumbnail{ co_await imagefile.GetThumbnailAsync(Windows::Storage::FileProperties::ThumbnailMode::PicturesView, 190, Windows::Storage::FileProperties::ThumbnailOptions::ResizeThumbnail) };

		Microsoft::UI::Xaml::Media::Imaging::BitmapImage thumbImage{};
		if (thumbnail)
			thumbImage.SetSource(thumbnail);
		else
			continue;

		auto&& thumbViewModel = make<PicViewer::implementation::thumbViewModel>(imagefile, thumbImage, imagefile.Name());
		_thumbViewModelVec.Append(thumbViewModel);
	}
}

```


## 5-3.MenuBarの下へGridViewを配置、②のVectorをBindし表示
・MainWindow.xamlを変更してGridViewを追加し、選んだフォルダにある画像のサムネイルを表示出来るように変更しましょう。変更するのはMainWindow.xamlのみです。

```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" />
            <RowDefinition Height="1*"/>
        </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>

        <GridView ItemsSource="{x:Bind viewModelVec}" Name="thumbGrid"  Grid.Row="1" IsItemClickEnabled="True" >
            <GridView.ItemTemplate>
                <DataTemplate x:Name="ImageTextDataTemplate" x:DataType="local:thumbViewModel">
                    <StackPanel Height="170" Width="200" Margin="5">
                        <Image Source="{x:Bind GetThumbImage}" Height="130" Width="190" />
                        <StackPanel Margin="0,10">
                            <TextBlock Text="{x:Bind GetImageName}"/>
                        </StackPanel>
                    </StackPanel>
                </DataTemplate>
            </GridView.ItemTemplate>
        </GridView>

    </Grid>
</Window>

```

・ここまで実装して適当なフォルダを表示させるとこんな感じになります。
![6-1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/131051/331cc933-9be4-6ae3-a944-ce7a079fce41.png)

[次へ](https://qiita.com/lilac0011/items/8be388a82fe7b8b7cee0)

[もくじへ](https://qiita.com/lilac0011/items/f53f7401ea7da31e3a0b)