MFCでもWinRTその8.　MFCアプリでもピクチャフォルダをサムネイル表示しよう（List,Gridの表示）

# 1.今回やること
・[前回](https://qiita.com/lilac0011/items/ca08fbb33dbf42121c4a)に作成したMFCWinRTThumbは仮表示させていました。
・今回はピクチャフォルダをサムネイル表示させます。以下のように。
![1-1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/131051/e3b8d703-c63a-51b1-87c0-2905d4a3a28a.png)


# 2. UWP部分の変更
・UWP部分の変更を行います。
・基本は[C++/WinRTでUWPその13](https://qiita.com/lilac0011/items/4c897212d236df43fee6)やったことをそのままやります。
・何も書いていなければUWP部分のThumbViewに関わる部分の変更です。

## 2-1. マニフェストの変更
・「Package.appmanifest」をダブルクリックして開いて機能からピクチャライブラリにチェックを入れます。
![2-1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/131051/c34eb3c4-2d4d-2848-e79f-879d0b7c2d90.png)

## 2-2. thumbViewModelの作成
・[前](https://qiita.com/lilac0011/items/4c897212d236df43fee6)と同じように①StorageFile、②サムネイル画像、③ファイル名を保存するViewModelを作成します。
・ここもいつものように、「プロジェクト」→「モジュールの追加」→「Visual C++」から「View Model」を選び名前を「thumbViewModel」へ変更して「追加」します。
![2-2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/131051/6af9e448-614a-1754-2bda-5d11ac800a5f.png)

## 2-3. thumbViewModel.idl .h .cppの変更
・追加したViewModelのコードを変更します。以下のように（コピペで何も変更していません）。
```XML:thumbViewModel.idl（変更後)
namespace ThumbView
{
    [Windows.UI.Xaml.Data.Bindable]
    runtimeclass thumbViewModel 
    {
        thumbViewModel();
        thumbViewModel(Windows.Storage.StorageFile imagefile, Windows.UI.Xaml.Media.Imaging.BitmapImage thunbimage, String imagename);

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

```CPP:thumbViewModel.h（変更後)
#pragma once

#include "thumbViewModel.g.h"


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

        thumbViewModel(
            Windows::Storage::StorageFile const& imagefile,
            Windows::UI::Xaml::Media::Imaging::BitmapImage const& thumbimage,
            hstring const& imagename
        ) :
            imageFile(imagefile),
            thumbImage(thumbimage),
            imageName(imagename)
        {}

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

        Windows::UI::Xaml::Media::Imaging::BitmapImage GetThumbImage() const
        {
            return thumbImage;
        }

        hstring GetImageName() const
        {
            return imageName;
        }

    private:
        Windows::Storage::StorageFile imageFile{ nullptr };
        Windows::UI::Xaml::Media::Imaging::BitmapImage thumbImage;
        hstring imageName;

    };
}

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

```

```CPP:thumbViewModel.cpp（変更後)
#include "pch.h"
#include "thumbViewModel.h"
#if __has_include("thumbViewModel.g.cpp")
#include "thumbViewModel.g.cpp"
#endif

namespace winrt::ThumbView::implementation
{

}

```

## 2-4. MainControl.xaml .idl .h .cppの変更
・ここも楽にコピペで行きたいところですが、いくつか注意点があります。
・[C++/WinRTでUWPその13](https://qiita.com/lilac0011/items/4c897212d236df43fee6)ではMainPage::OnNavigatedTo()をオーバーライドして起動時の処理（サムネイル画像の読み込み等）を記述しました。
・[アプリの事前起動の処理](https://learn.microsoft.com/ja-jp/windows/uwp/launch-resume/handle-app-prelaunch)に書いてある内容ですが、OnLaunched()をオーバーライドすると、事前起動の処理を記述できます。UWPアプリではApp.h/.cppでOnLaunched()をオーバーライドして、その中でrootFrame.Navigate()を呼んでいるので、MainPage::OnNavigatedTo()をオーバーライドすると起動時の処理として記述できました。以下のような感じで。
```CPP:App.cpp（thumb_pic_1)
void App::OnLaunched(LaunchActivatedEventArgs const& e)
{
    Frame rootFrame{ nullptr };
    auto content = Window::Current().Content();
    if (content)
    {
        rootFrame = content.try_as<Frame>();
    }

    if (rootFrame == nullptr)
    {
        rootFrame = Frame();

        rootFrame.NavigationFailed({ this, &App::OnNavigationFailed });

        if (e.PreviousExecutionState() == ApplicationExecutionState::Terminated)
        {
        }

        if (e.PrelaunchActivated() == false)
        {
            if (rootFrame.Content() == nullptr)
            {
                // ここで呼んでます
                rootFrame.Navigate(xaml_typename<thumb_pic_1::MainPage>(), box_value(e.Arguments()));
            }
            Window::Current().Content(rootFrame);
            Window::Current().Activate();
        }
    }
    else
    {
        if (e.PrelaunchActivated() == false)
        {
            if (rootFrame.Content() == nullptr)
            {
                // ここで呼んでます
                rootFrame.Navigate(xaml_typename<thumb_pic_1::MainPage>(), box_value(e.Arguments()));
            }
            Window::Current().Activate();
        }
    }
}
```


・今回のUWP側のApp.cppは以下に書き換えました。
```CPP:ThumbView::App.cpp（変更後)
App.cpp（変更後)
#include "pch.h"
#include "App.h"
#include "App.g.cpp"

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

namespace winrt::ThumbView::implementation
{
    App::App()
    {
        Initialize();
        AddRef();
        m_inner.as<::IUnknown>()->Release();
    }
    App::~App()
    {
        Close();
    }
}
```

・ThumbViewではOnLaunched()をオーバーライドしていないので、MainControlでOnNavigatedTo()をオーバーライドしても起動時に呼ばれません。
・App::OnLaunched()とMainControl::OnNavigatedTo()の二つをオーバーライドするのも面倒なので、MainControlに追加する予定の
　Windows::Foundation::Collections::IObservableVector＜Windows::Foundation::IInspectable＞ thumbViewModelVecと
　サムネイル関連の情報を取得するメンバ関数をstaticにして、App.cppのOnLaunched()から呼ぶようにしてしまいましょう。
・では以下にソースを。

・xamlはほぼ変更はありません。Classやlocal等細かいところが変わっているだけですね。
```XML:MainControl.xaml（変更後)
<UserControl
    x:Class="ThumbView.MainControl"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="using:ThumbView"
    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="1*" />
            <RowDefinition Height="1*"/>
        </Grid.RowDefinitions>
        <ListView x:Name="list1" ItemsSource="{x:Bind ThumbViewModelVec}" Grid.Row="0">
            <ListView.ItemTemplate>
                <DataTemplate x:Name="singleLineTemplate" x:DataType="local:thumbViewModel">
                    <StackPanel Orientation="Horizontal" Height="160">
                        <Image Source="{x:Bind GetThumbImage}" Height="150" Width="150" VerticalAlignment="Center"/>
                        <TextBlock Text="{x:Bind Path=GetImageName}" VerticalAlignment="Center" Style="{ThemeResource BaseTextBlockStyle}" Foreground="{ThemeResource SystemControlPageTextBaseHighBrush}" Margin="12,0,0,0"/>
                    </StackPanel>
                </DataTemplate>
            </ListView.ItemTemplate>
        </ListView>

        <GridView ItemsSource="{x:Bind ThumbViewModelVec}"  Grid.Row="1" >
            <GridView.ItemTemplate>
                <DataTemplate x:Name="ImageTextDataTemplate" x:DataType="local:thumbViewModel">
                    <StackPanel Height="200" Width="180" Margin="12">
                        <Image Source="{x:Bind GetThumbImage}" Height="150" Width="150" Stretch="UniformToFill"/>
                        <StackPanel Margin="0,12">
                            <TextBlock Text="{x:Bind Path=GetImageName}"/>
                        </StackPanel>
                    </StackPanel>
                </DataTemplate>
            </GridView.ItemTemplate>
            <GridView.ItemsPanel>
                <ItemsPanelTemplate>
                    <ItemsWrapGrid MaximumRowsOrColumns="10" Orientation="Horizontal"/>
                </ItemsPanelTemplate>
            </GridView.ItemsPanel>
        </GridView>

    </Grid>
</UserControl>
```

・ここもstaticだからといってほぼ変わりません。
```XML:MainControl.idl（変更後)
import "thumbViewModel.idl";

namespace ThumbView
{
    [default_interface]
    runtimeclass MainControl : Windows.UI.Xaml.Controls.UserControl
    {
        MainControl();
        Windows.Foundation.Collections.IObservableVector<IInspectable> ThumbViewModelVec{ get; };
    }
}
```

・宣言でstaticになっているでしょ。
```CPP:MainControl.h（変更後)
#pragma once

#include "MainControl.g.h"

#include "thumbViewModel.h"

namespace winrt::ThumbView::implementation
{
    struct MainControl : MainControlT<MainControl>
    {
        MainControl();

        Windows::Foundation::Collections::IObservableVector<Windows::Foundation::IInspectable> ThumbViewModelVec() const
        {
            return thumbViewModelVec;
        }

        //ここで、StorageFile、サムネイル画像、ファイル名を集めるよ static
        static Windows::Foundation::IAsyncAction AppendViewModelAsync();

        //サムネイル画像を取得するよ static
        static Windows::Foundation::IAsyncOperation<Windows::UI::Xaml::Media::Imaging::BitmapImage> GetThumbnailAsync(Windows::Storage::StorageFile m_imageFile);


    private:
        //サムネイル等の保存用だよ static
        static  Windows::Foundation::Collections::IObservableVector<Windows::Foundation::IInspectable> thumbViewModelVec;
    };

    
}

namespace winrt::ThumbView::factory_implementation
{
    struct MainControl : MainControlT<MainControl, implementation::MainControl>
    {
    };
}

```

・staticにしたIObservableVectorの初期化を追加しただけですね。
```CPP:MainControl.cpp（変更後)
#include "pch.h"
#include "MainControl.h"
#if __has_include("MainControl.g.cpp")
#include "MainControl.g.cpp"
#endif

#include <winrt/Windows.UI.Xaml.Media.Imaging.h>
#include <winrt/Windows.Storage.Search.h>

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

namespace winrt::ThumbView::implementation
{
    //staticなので初期化を追加
    Windows::Foundation::Collections::IObservableVector<Windows::Foundation::IInspectable> MainControl::thumbViewModelVec{ nullptr };

    MainControl::MainControl()
    {
        thumbViewModelVec = winrt::single_threaded_observable_vector<IInspectable>();
        InitializeComponent();

    }

    Windows::Foundation::IAsyncAction MainControl::AppendViewModelAsync()
    {
        //サーチするのは「jpg」「png」「gif」
        Windows::Storage::Search::QueryOptions searchoptions{};

        searchoptions.FolderDepth(Windows::Storage::Search::FolderDepth::Deep);

        searchoptions.FileTypeFilter().Append(L".jpg");
        searchoptions.FileTypeFilter().Append(L".png");
        searchoptions.FileTypeFilter().Append(L".gif");

        //ピクチャーフォルダをサーチ
        Windows::Storage::StorageFolder picturesfolder = Windows::Storage::KnownFolders::PicturesLibrary();

        //上記の条件に合うのを探す
        auto searchresult = picturesfolder.CreateFileQueryWithOptions(searchoptions);
        auto imagefiles = co_await searchresult.GetFilesAsync();

        if (thumbViewModelVec.Size() != 0)
            co_return;

        //StorageFileからサムネイル画像とファイル名を取得して、ThumbViewModelを作成し、ThumbViewModelVecへAppend（追加）
        for (auto&& file : imagefiles)
        {
            if (file.Provider().Id() == L"computer")
            {
                auto thumbimage = co_await GetThumbnailAsync(file);
                auto thumbview = winrt::make<thumbViewModel>(file, thumbimage, file.DisplayName());
                thumbViewModelVec.Append(thumbview);
            }
        }
    }

    Windows::Foundation::IAsyncOperation<Windows::UI::Xaml::Media::Imaging::BitmapImage> MainControl::GetThumbnailAsync(Windows::Storage::StorageFile imagefile)
    {
        auto thumbnail = co_await imagefile.GetThumbnailAsync(Windows::Storage::FileProperties::ThumbnailMode::PicturesView);
        Windows::UI::Xaml::Media::Imaging::BitmapImage thumbnailimage{};
        thumbnailimage.SetSource(thumbnail);
        thumbnail.Close();

        co_return thumbnailimage;
    }

}
```

## 2-5. App.h .cppの変更
・というわけで、void OnLaunched()を追加します。
```CPP:App.h（変更後)
#pragma once
#include "App.g.h"
#include "App.base.h"

namespace winrt::ThumbView::implementation
{
    class App : public AppT2<App>
    {
    public:
        App();
        ~App();

        //ここ追加
        void OnLaunched(Windows::ApplicationModel::Activation::LaunchActivatedEventArgs const&);
    };
}
namespace winrt::ThumbView::factory_implementation
{
    class App : public AppT<App, implementation::App>
    {
    };
}
```

・OnLaunched()でMainControl::AppendViewModelAsync()を呼び出すよ～～
```CPP:App.cpp（変更後)
#include "pch.h"
#include "App.h"
#include "App.g.cpp"

#include "MainControl.h"


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


using namespace ThumbView::implementation;

namespace winrt::ThumbView::implementation
{
    App::App()
    {
        Initialize();
        AddRef();
        m_inner.as<::IUnknown>()->Release();
    }
    App::~App()
    {
        Close();
    }

    void App::OnLaunched(Windows::ApplicationModel::Activation::LaunchActivatedEventArgs const& e)
    {
        //呼び出すよ～～
        MainControl::AppendViewModelAsync();
    }
}
```

・ビルド～実行してエラーが出なければOK！
![2-3.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/131051/666209ee-30ed-8d18-8a9e-819619292d6d.png)
・こんな感じでピクチャフォルダをサムネイル表示してくれるはず。
![1-1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/131051/e3b8d703-c63a-51b1-87c0-2905d4a3a28a.png)

・後はメモリーリークが見つかった！と言われるので、後始末をして下さい。後始末は宿題です！

・[GitHub](https://github.com/yoshiyoshi-git/MFCWinRTThumb)はこちら。
・[目次へ](https://qiita.com/lilac0011/items/f53f7401ea7da31e3a0b)