UWP PhotoLab サンプル アプリの Windows App SDK の移行 (C#)

このトピックは、C# UWP PhotoLab サンプル アプリを取得して、それを Windows App SDK に移行するケース スタディです。

まず、UWP サンプル アプリのリポジトリを複製し、Visual Studio でソリューションを開きます。

重要

移行プロセスに取り組む際の考慮事項と戦略や、移行用の開発環境を設定する方法については、「全体的な移行戦略」を参照してください。 移行を試みる前に、「UWP から WinUI 3 への移行時にサポートされる機能」を参照して、アプリに必要なすべての機能がサポートされていることを確認することが特に重要です。

Windows App SDK 用のツールをインストールする

開発コンピューターをセット アップするには、「Windows App SDK 用のツールをインストールする」を参照してください。

重要

リリース ノートのトピックと、「Windows App SDK のリリース チャネル」のトピックをご覧ください。 各チャネルのリリース ノートがあります。 これらのリリース ノートに記載されている制限事項と既知の問題を必ず確認してください。このケース スタディを実行したり、移行したアプリを実行したりした結果に影響を与える可能性があるためです。

新しいプロジェクトを作成する

Visual Studio で、[Blank App, Packaged (WinUI 3 in Desktop)] (空のアプリ、パッケージ (WinUI 3 in Desktop)) プロジェクト テンプレートを使用して、新しい C# アプリを作成します。 プロジェクトに PhotoLabWinUI という名前を付け、[ソリューションとプロジェクトを同じディレクトリに配置する] チェック ボックスをオフにします。 クライアント オペレーティング システムの最新リリース (プレビューではないもの) をターゲットにすることができます。

注意

サンプル プロジェクトの UWP バージョン (リポジトリから複製したもの) を "ソース" ソリューション/プロジェクトと呼びます。 Windows App SDK バージョンを "ターゲット" ソリューション/プロジェクトと呼びます。

コードを移行する順序

MainPage は、アプリの重要な目立つ部分です。 しかし、それを移行することから始めると、MainPageDetailPage ビューに依存し、その DetailPageImageFileInfo モデルに依存していることがすぐにわかります。 そのため、今回のチュートリアルでは、このアプローチを採用します。

  • まず、アセット ファイルをコピーします。
  • 次に、ImageFileInfo モデルを移行します。
  • 次に、App クラスを移行します (DetailPageMainPage、および LoadedImageBrush が依存するように変更する必要があるためです)。
  • 次に、LoadedImageBrush クラスを移行します。
  • 次に、ビューの移行を開始します。最初に DetailPage から始めます。
  • 最後に、MainPage ビューを移行します。

アセット ファイルをコピーする

  1. Visual Studio のターゲット プロジェクトのソリューション エクスプローラーで、Assets フォルダーを右クリックし、Samples という名前の新しいフォルダーを追加します。

  2. ソース プロジェクトの複製で、エクスプローラーで、Windows-appsample-photo-lab>PhotoLab>Assets フォルダーを見つけます。 そのフォルダーには、7 つの資産ファイルのほか、サンプル画像を含む Samples という名前のサブフォルダーがあります。 これらの 7 つの資産ファイルと Samples サブフォルダーを選択し、クリップボードにコピーします。

  3. また、エクスプローラーで、作成したターゲット プロジェクト内の対応するフォルダーを見つけます。 そのフォルダーへのパスは PhotoLabWinUI>PhotoLabWinUI>Assets です。 コピーした資産ファイルとサブフォルダーをそのフォルダーに貼り付けます。このとき、コピー先に既に存在するファイルを置き換えることを確認するプロンプトを受け入れます。

  4. Visual Studio のターゲット プロジェクトのソリューション エクスプローラーで、Assets フォルダーを展開すると、Samples フォルダーと Samples サブフォルダーの内容 (先ほど貼り付けたもの) が表示されます。 アセット ファイルの上にマウス ポインターを置きます。 それぞれにサムネイル プレビューが表示されるため、アセット ファイルが正しく置き換えられたか、または追加されたことを確認します。

ImageFileInfo モデルを移行する

ImageFileInfo は、(モデル、ビュー、およびビューモデルという意味において) 写真などの画像ファイルを表す "モデル" です。

ImageFileInfo のソース コード ファイルをコピーする

  1. ソース プロジェクトの複製で、エクスプローラーで、Windows-appsample-photo-lab>PhotoLab フォルダーを見つけます。 このフォルダーには、ソース コード ファイル ImageFileInfo.cs があります。このファイルには、ImageFileInfo の実装が含まれています。 このファイルを選択し、クリップボードにコピーします。

  2. Visual Studio でターゲット プロジェクト ノードを右クリックし、[エクスプローラーでフォルダーを開く] をクリックします。 これにより、エクスプローラーでターゲット プロジェクト フォルダーが開きます。 コピーしたファイルをそのフォルダーに貼り付けます。

ImageFileInfo のソース コードを移行する

  1. 先ほど貼り付けた ImageFileInfo.cs ファイル内で、次の語句を検索して置換します (大文字と小文字を区別、単語単位)。
  • namespace PhotoLab =>namespace PhotoLabWinUI
  • Windows.UI.Xaml =>Microsoft.UI.Xaml

Windows.UI.Xaml は、UWP XAML の名前空間です。Microsoft.UI.Xaml は、WinUI XAML の名前空間です。

Note

UWP API を Windows App SDK にマッピングする」トピックでは、UWP API から同等の Windows App SDK へのマッピングを行います。 上記で行った変更は、移行プロセス中に必要な名前空間名の変更の例です。

  1. 次に、ターゲット ソリューションをビルドできることを確認します (ただし、まだ実行しないでください)。

App クラスを移行する

  1. ソース プロジェクトで、App.xaml<Application.Resources> 要素内で次の 4 行を見つけます。 これらをコピーし、ターゲット プロジェクトに貼り付けます。
<SolidColorBrush x:Key="RatingControlSelectedForeground" Color="White"/>
<!--  Window width adaptive breakpoints.  -->
<x:Double x:Key="MinWindowBreakpoint">0</x:Double>
<x:Double x:Key="MediumWindowBreakpoint">641</x:Double>
<x:Double x:Key="LargeWindowBreakpoint">1008</x:Double>

Note

ターゲット プロジェクトではソース プロジェクトとは異なる (より簡単な) ナビゲーションを使用するため、ソース プロジェクトの App.xaml.cs からさらにコードをコピーする必要はありません。

  1. ターゲット プロジェクトの App では、メイン ウィンドウ オブジェクトがそのプライベート フィールド m_window に格納されます。 移行プロセスの後半 (ソース プロジェクトでの Window.Current の使用を移行するとき) では、そのプライベート フィールドがパブリック静的プロパティであると便利です。 そこで、次に示すように、m_window フィールドを Window プロパティに置き換え、参照を m_window に変更します。
// App.xaml.cs
public partial class App : Application
{
    ...
    protected override void OnLaunched(Microsoft.UI.Xaml.LaunchActivatedEventArgs args)
    {
        Window = new MainWindow();
        Window.Activate();
    }

    public static MainWindow Window { get; private set; }
}
  1. 移行プロセスの後半 (FileSavePickerを表示するコードを移行するとき) では、App によってメイン ウィンドウの "ハンドル" (HWND) が公開されると便利です。 そこで、次に示すように、WindowHandle プロパティを追加し、OnLaunched メソッドでこれを初期化します。
// App.xaml.cs
public partial class App : Application
{
    ...
    protected override void OnLaunched(Microsoft.UI.Xaml.LaunchActivatedEventArgs args)
    {
        Window = new MainWindow();
        Window.Activate();
        WindowHandle = WinRT.Interop.WindowNative.GetWindowHandle(Window);
    }

    public static IntPtr WindowHandle { get; private set; }
}

LoadedImageBrush モデルを移行する

LoadedImageBrush は、XamlCompositionBrushBase の特殊化です。 PhotoLab サンプル アプリでは、LoadedImageBrush クラスを使用して写真に効果を適用します。

Win2D NuGet パッケージを参照する

LoadedImageBrush のコードをサポートするために、ソース プロジェクトは Win2D に依存しています。 そのため、ターゲット プロジェクトでは Win2D への依存関係も必要になります。

Visual Studio のターゲット ソリューションで、[ツール]>[NuGet パッケージ マネージャー]>[ソリューションの NuGet パッケージの管理]>[参照] の順にクリックし、「Microsoft.Graphics.Win2D」と入力するか、これを貼り付けます。 検索結果で適切な項目を選択します。PhotoLabWinUI プロジェクトのチェック ボックスをオンにし、[インストール] をクリックして、パッケージをこのプロジェクトにインストールします。

LoadedImageBrush のソース コード ファイルをコピーする

ImageFileInfo.cs をコピーしたのと同じ方法で、LoadedImageBrush.cs をソース プロジェクトからターゲット プロジェクトにコピーします。

LoadedImageBrush のソース コードを移行する

  1. 先ほど貼り付けた LoadedImageBrush.cs ファイル内で、次の語句を検索して置換します (大文字と小文字を区別、単語単位)。
  1. ターゲット ソリューションをビルドできることを確認します (ただし、まだ実行しないでください)。

DetailPage ビューを移行する

DetailPage は、Win2D 効果の切り替え、設定、連結が行われるフォト エディター ページを表すクラスです。 MainPage で写真のサムネイルを選択すると、フォト エディター ページが表示されます。 DetailPage は、(モデル、ビュー、およびビューモデルという意味において) "モデル" です。

DetailPage ソース コード ファイルをコピーする

前の手順でファイルをコピーしたのと同じ方法で、DetailPage.xamlDetailPage.xaml.cs をソース プロジェクトからターゲット プロジェクトにコピーします。

DetailPage ソース コードを移行する

  1. 先ほど貼り付けた DetailPage.xaml ファイル内で、次の語句を検索して置換します (大文字と小文字を区別、単語単位)。
  • PhotoLab =>PhotoLabWinUI
  1. 先ほど貼り付けた DetailPage.xaml.cs ファイル内で、次の語句を検索して置換します (大文字と小文字を区別、単語単位)。
  • namespace PhotoLab =>namespace PhotoLabWinUI
  • Windows.UI.Colors =>Microsoft.UI.Colors
  • Windows.UI.Xaml =>Microsoft.UI.Xaml
  1. 次の手順では、ContentDialog と Popup で説明されている変更を行います。 そこで、引き続き DetailPage.xaml.cs 内で、ShowSaveDialog メソッドの行 ContentDialogResult result = await saveDialog.ShowAsync(); の "直前" にこのコードを追加します。
if (Windows.Foundation.Metadata.ApiInformation.IsApiContractPresent("Windows.Foundation.UniversalApiContract", 8))
{
    saveDialog.XamlRoot = this.Content.XamlRoot;
}
  1. 引き続き DetailPage.xaml.cs 内で、OnNavigatedTo メソッドから次の 2 行のコードを削除します。 これらの 2 行だけです。このケース スタディの後半で、削除した戻るボタン機能を再導入します。
...
SystemNavigationManager.GetForCurrentView().AppViewBackButtonVisibility =
    AppViewBackButtonVisibility.Visible;
...
SystemNavigationManager.GetForCurrentView().AppViewBackButtonVisibility = 
    AppViewBackButtonVisibility.Collapsed;
...
  1. この手順では、「MessageDialog および Pickers」で説明されている変更を加えます。 引き続き DetailPage.xaml.cs 内で、ExportImage メソッドの行 var outputFile = await fileSavePicker.PickSaveFileAsync(); の "直前" にこのコード行を追加します。
WinRT.Interop.InitializeWithWindow.Initialize(fileSavePicker, App.WindowHandle);

MainPageDetailPage に依存しています。これが、DetailPage を最初に移行した理由です。 ただし、DetailPageMainPage に依存しているため、まだビルドできません。

MainPage ビューを移行する

アプリのメイン ページは、アプリを実行したときに最初に表示されるビューを表しています。 このページには、サンプル アプリに組み込まれている Samples フォルダーから写真が読み込まれ、タイル状のサムネイル ビューが表示されます。

MainPage ソース コード ファイルをコピーする

前の手順でファイルをコピーしたのと同じ方法で、MainPage.xamlMainPage.xaml.cs をソース プロジェクトからターゲット プロジェクトにコピーします。

MainPage のソース コードを移行する

  1. 先ほど貼り付けた MainPage.xaml ファイル内で、次の語句を検索して置換します (大文字と小文字を区別、単語単位)。
  • PhotoLab =>PhotoLabWinUI
  1. 引き続き MainPage.xaml 内で、マークアップ animations:ReorderGridAnimation.Duration="400" を見つけて削除します。

  2. 先ほど貼り付けた MainPage.xaml.cs ファイル内で、次の語句を検索して置換します (大文字と小文字を区別、単語単位)。

  • namespace PhotoLab =>namespace PhotoLabWinUI
  • Windows.UI.Xaml =>Microsoft.UI.Xaml
  1. この手順では、「ContentDialog および Popup」で説明されている変更を加えます。 そこで、引き続き MainPage.xaml.cs 内で、GetItemsAsync メソッドの行 ContentDialogResult resultNotUsed = await unsupportedFilesDialog.ShowAsync(); の "直前" にこのコードを追加します。
if (Windows.Foundation.Metadata.ApiInformation.IsApiContractPresent("Windows.Foundation.UniversalApiContract", 8))
{
    unsupportedFilesDialog.XamlRoot = this.Content.XamlRoot;
}
  1. 引き続き MainPage.xaml.cs 内で、OnNavigatedTo メソッドから次のコード行を削除します。
SystemNavigationManager.GetForCurrentView().AppViewBackButtonVisibility =
    AppViewBackButtonVisibility.Collapsed;

このケース スタディの後半で、削除した戻るボタン機能を再導入します。

  1. ターゲット ソリューションをビルドできることを確認します (ただし、まだ実行しないでください)。

PhotoLab サンプル アプリでは、ナビゲーション ロジックを使用して、最初に MainPage (次に、MainPageDetailPage の間) に移動します。 ナビゲーションが必要 (および不要) な Windows App SDK アプリの詳細については、「ページ ナビゲーションを実装する必要がありますか?」を参照してください。

そこで、次に行う変更でこのナビゲーションをサポートします。

  1. MainWindow.xaml 内で、<StackPanel> 要素を削除し、名前付きの <Frame> 要素のみに置き換えます。 結果は次のようになります。
<Window ...>
    <Frame x:Name="rootFrame"/>
</Window>
  1. MainWindow.xaml.cs 内で、myButton_Click メソッドを削除します。

  2. 引き続き MainWindow.xaml.cs 内で、次のコード行をコンストラクターに追加します。

public sealed partial class MainWindow : Window
{
    public MainWindow()
    {
        this.InitializeComponent();
        rootFrame.Navigate(typeof(MainPage));
    }
}
  1. ターゲット ソリューションをビルドできることを確認します (ただし、まだ実行しないでください)。

戻るボタン機能の復元

  1. DetailPage.xaml では、ルート要素は RelativePanel です。 その RelativePanel 内の StackPanel 要素の直後に次のマークアップを追加します。
<AppBarButton x:Name="BackButton" Click="BackButton_Click" Margin="0,0,12,0">
    <SymbolIcon Symbol="Back"/>
</AppBarButton>
  1. DetailPage.xaml.cs 内で、次の 2 行のコードを OnNavigatedTo メソッド内の示されている場所に追加します。
if (this.Frame.CanGoBack)
{
    BackButton.Visibility = Microsoft.UI.Xaml.Visibility.Visible;
}
else
{
    BackButton.Visibility = Microsoft.UI.Xaml.Visibility.Collapsed;
}
  1. 引き続き DetailPage.xaml.cs 内で、次のイベント ハンドラーを追加します。
private void BackButton_Click(object sender, Microsoft.UI.Xaml.RoutedEventArgs e)
{
    Frame.GoBack();
}

移行したアプリをテストする

次に、プロジェクトをビルドし、アプリを実行してテストします。 画像を選択して、ズーム レベルを設定し、効果を選択して構成します。