UWP PhotoLab 샘플 앱(C#)의 Windows 앱 SDK 마이그레이션

이 항목은 C# UWP PhotoLab 샘플 앱을 가져와 Windows 앱 SDK로 마이그레이션하는 사례 연구입니다.

먼저 UWP 샘플 앱의 리포지토리를 복제하고 Visual Studio에서 솔루션을 엽니다.

Important

마이그레이션 프로세스에 접근하기 위한 고려 사항 및 전략, 마이그레이션을 위한 개발 환경 설정 방법은 전체 마이그레이션 전략을 참조하세요. 마이그레이션을 시도하기 전에 앱에 필요한 모든 기능이 지원되는지 확인할 수 있도록 UWP에서 WinUI 3 으로 포팅할 때 지원되는 기능을 확인하는 것이 특히 중요합니다.

Windows 앱 SDK용 도구 설치

개발 컴퓨터를 설정하려면 Windows 앱 SDK용 도구 설치를 참조하세요.

Important

Windows 앱 SDK 릴리스 채널 항목과 함께 릴리스 정보 항목을 찾을 수 있습니다. 각 채널에 대한 릴리스 정보가 있습니다. 해당 릴리스 정보에서 제한 사항 및 알려진 문제를 확인합니다. 이러한 사항은 이 사례 연구를 따르거나 마이그레이션된 앱을 실행한 결과에 영향을 미칠 수 있기 때문입니다.

새 프로젝트 만들기

Visual Studio에서 Blank App, Packaged(데스크톱의 WinUI 3) 프로젝트 템플릿에서 새 C# 프로젝트를 만듭니다. 프로젝트 이름을 PhotoLabWinUI로 지정하고 같은 디렉터리에 솔루션 및 프로젝트 배치를 선택 취소합니다. 클라이언트 운영 체제의 최신 릴리스(미리 보기 아님)를 대상으로 지정할 수 있습니다.

참고 항목

샘플 프로젝트(해당 리포지토리에서 복제한 프로젝트)의 UWP 버전을 원본 솔루션/프로젝트로 참조할 예정입니다. Windows 앱 SDK 버전을 대상 솔루션/프로젝트라고 합니다.

코드를 마이그레이션하는 순서

MainPage는 앱에서 중요하고 눈에 띄는 부분입니다. 그러나 마이그레이션을 시작한다면 MainPageDetailPage 보기에 종속된다는 것을 곧 알게 될 것입니다. DetailPage에는 ImageFileInfo 모델에 대한 종속성이 있습니다. 따라서 이 연습에서는 이 접근 방식을 사용합니다.

  • 자산 파일을 복사하는 것으로 시작할 예정입니다.
  • 그런 다음 ImageFileInfo 모델을 마이그레이션합니다.
  • 다음으로 App 클래스를 마이그레이션합니다(DetailPage, MainPageLoadedImageBrush가 종속되도록 변경 필요).
  • 그런 다음 LoadedImageBrush 클래스를 마이그레이션합니다.
  • 그런 다음, 먼저 DetailPage부터 시작하여 보기 마이그레이션을 시작합니다.
  • MainPage 보기를 마이그레이션하는 것으로 마무리할 예정입니다.

자산 파일 복사

  1. Visual Studio의 대상 프로젝트에 있는 솔루션 탐색기에서 Assets 폴더를 마우스 오른쪽 단추로 클릭하고 Samples라는 새 폴더를 추가합니다.

  2. 원본 프로젝트의 복제본에서 파일 탐색기에서 Windows-appsample-photo-lab>PhotoLab>자산 폴더를 찾습니다. 이 폴더에는 샘플 이미지가 포함된 Samples라는 하위 폴더와 함께 7개의 자산 파일이 있습니다. 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의 네임스페이스입니다.

참고 항목

UWP API를 Windows 앱 SDK에 매핑 항목에서는 UWP API를 해당하는 Windows 앱 SDK에 매핑하는 방법을 제공합니다. 위에서 변경한 내용은 마이그레이션 프로세스 중에 필요한 네임스페이스 이름 변경의 예입니다.

  1. 이제 대상 솔루션을 빌드할 수 있는지 확인합니다(아직 실행하지는 않음).

App 클래스 마이그레이션

  1. 원본 프로젝트의 App.xaml에 있는 <Application.Resources> 요소에서 다음 네 줄을 찾습니다. 복사하여 대상 프로젝트에 붙여넣습니다.
<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>

참고 항목

대상 프로젝트는 원본 프로젝트와 다른(그리고 더 간단한) 탐색을 사용하므로 원본 프로젝트의 App.xaml.cs에서 추가 코드를 복사할 필요가 없습니다.

  1. 대상 프로젝트에서 은 주 창 개체를 프라이빗 필드인 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를 표시하는 코드를 마이그레이션할 때) 이 주 창의 핸들(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 모델 마이그레이션

LoadedImageBrushXamlCompositionBrushBase의 특수화입니다. 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.csOnNavigatedTo 메서드에서 다음 두 줄의 코드를 삭제합니다. 이 두 줄만 삭제합니다. 이 사례 연구의 뒷부분에서 방금 제거한 뒤로 단추 기능을 다시 도입할 것입니다.
...
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.csOnNavigatedTo 메서드에서 다음 코드 줄을 삭제합니다.
SystemNavigationManager.GetForCurrentView().AppViewBackButtonVisibility =
    AppViewBackButtonVisibility.Collapsed;

이 사례 연구의 뒷부분에서 방금 제거한 뒤로 단추 기능을 다시 도입합니다.

  1. 대상 솔루션을 빌드할 수 있는지 확인합니다(아직 실행하지는 않음).

PhotoLab 샘플 앱은 탐색 논리를 사용하여 처음에 MainPage(그리고 MainPageDetailPage 사이)로 이동합니다. 탐색이 필요한 Windows 앱 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입니다. StackPanel 요소 바로 뒤에 있는 해당 RelativePanel 내부에 다음 태그를 추가합니다.
<AppBarButton x:Name="BackButton" Click="BackButton_Click" Margin="0,0,12,0">
    <SymbolIcon Symbol="Back"/>
</AppBarButton>
  1. DetailPage.xaml.cs에서 다음 두 줄의 코드를 표시된 위치에서 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();
}

마이그레이션된 앱 테스트

이제 프로젝트를 빌드하고 앱을 실행하여 테스트합니다. 이미지를 선택하고 확대/축소 수준을 설정하고 효과를 선택하고 구성합니다.