XAML Islands를 사용하여 C# WPF 앱에서 UWP XAML 컨트롤 호스트

중요

이 토픽은 CommunityToolkit/Microsoft.Toolkit.Win32 GitHub 리포지토리의 형식을 사용하거나 다룹니다. XAML Islands 지원에 대한 중요한 정보는 해당 리포지토리의 XAML Islands 알림을 참조하세요.

이 토픽에서 XAML Islands를 사용하여 UWP(유니버설 Windows 플랫폼) XAML 컨트롤(즉, Windows SDK에서 제공하는 자사 컨트롤)을 호스트하는 C# WPF(Windows Presentation Foundation) 앱(.NET Core 3.1 대상)을 빌드하는 방법을 볼 수 있습니다. 이러한 작업을 수행하는 두 가지 방법이 있습니다.

  • wrapped controls(Windows Community Toolkit에서 사용 가능)을 사용하여 UWP InkCanvasInkToolbar 컨트롤을 호스팅하는 방법을 보여 줍니다. 래핑된 컨트롤은 유용한 UWP XAML 컨트롤에 대한 작은 세트의 인터페이스 및 기능을 래핑합니다. WPF 또는 Windows Forms 프로젝트의 디자인 화면에 래핑된 컨트롤을 직접 추가한 다음, 다른 WPF 또는 Windows Forms 컨트롤처럼 디자이너에서 사용할 수 있습니다.

  • 또한 WindowsXamlHost 컨트롤(Windows Community Toolkit에서 사용 가능)을 사용하여 UWP CalendarView 컨트롤을 호스팅하는 방법을 보여 줍니다. UWP XAML 컨트롤의 작은 세트만 래핑된 컨트롤로 사용할 수 있기 때문에 WindowsXamlHost를 사용하여 모든 UWP XAML 컨트롤을 호스트할 수 있습니다.

WPF 앱에서 UWP XAML 컨트롤을 호스팅하는 프로세스는 Windows Forms 앱과 비슷합니다.

중요

XAML Islands(래핑된 컨트롤 또는 WindowsXamlHost)를 사용하여 UWP XAML 컨트롤을 호스팅하는 것은 .NET Core 3.x를 대상으로 하는 앱에서만 지원됩니다. XAML Islands는 .NET을 대상으로 하는 앱 또는 .NET Framework 버전을 대상으로 하는 앱에서 지원되지 않습니다.

WPF 또는 Windows Forms 앱에서 UWP XAML 컨트롤을 호스팅하려면 솔루션에 다음 구성 요소가 있는 것이 좋습니다. 이 토픽에서 이러한 각 구성 요소를 만드는 방법에 대한 지침을 제공합니다.

  • WPF 또는 Windows Forms 앱에 대한 프로젝트 및 소스 코드.

  • XamlApplication에서 파생되는 루트 Application 클래스를 정의하는 UWP 앱 프로젝트. Microsoft.Toolkit.Win32.UI.XamlHost.XamlApplication 클래스는 Windows Community Toolkit에서 사용할 수 있습니다). XamlApplication 파생 애플리케이션 클래스를 WPF 또는 Windows Forms Visual Studio 솔루션의 일부인 별도의 UWP 앱 프로젝트로 정의하는 것이 좋습니다.

    참고

    자사 UWP XAML 컨트롤을 호스트하기 위해 WPF 또는 Windows Forms 프로젝트에서 XamlApplication 파생 개체를 사용할 수 있도록 하는 것은 실제로 필요하지 않습니다. 그러나 사용자 지정 UWP XAML 컨트롤을 검색, 로드 및 호스트하려면 필요합니다. 따라서 XAML Island 시나리오의 전체 범위를 지원하려면 XAML Islands를 사용하는 모든 솔루션에서 항상 XamlApplication 파생 개체를 정의하는 것을 권장합니다.

    참고

    솔루션은 XamlApplication 파생 개체를 정의하는 프로젝트를 하나만 포함할 수 있습니다. 해당 프로젝트는 XAML Islands를 통해 UWP XAML 컨트롤을 호스트하는 다른 라이브러리 및 프로젝트를 참조해야 합니다.

WPF 프로젝트 만들기

다음 지침에 따라 새 WPF 프로젝트를 만들고 XAML Islands를 호스팅하도록 구성할 수 있습니다. 기존 WPF 프로젝트가 있는 경우 프로젝트에 대해 이러한 단계 및 코드 예제를 적용할 수 있습니다.

  1. 아직 설치하지 않은 경우 최신 버전의 .NET Core 3.1을 설치하세요.

  2. Visual Studio의 WPF 애플리케이션 프로젝트 템플릿에서 새 C# 프로젝트를 만듭니다. 이 토픽의 단계 또는 소스 코드를 편집할 필요가 없도록 프로젝트 이름MyWPFApp으로 설정합니다. 프레임워크.NET Core 3.1*로 설정하고 만들기를 클릭합니다.

중요

WPF 앱(.NET Framework) 프로젝트 템플릿을 사용하지 마세요.

WPF 프로젝트 구성

  1. 다음 단계에서는 패키지 참조를 사용하도록 설정합니다.

    1. Visual Studio에서 도구>NuGet 패키지 관리자>패키지 관리자 설정을 클릭합니다.
    2. 오른쪽에서 패키지 관리>기본 패키지 관리 형식 설정을 찾아 PackageReference로 설정합니다.
  2. 다음 단계를 사용하여 Microsoft.Toolkit.Wpf.UI.Controls NuGet 패키지를 설치합니다.

    1. 솔루션 탐색기에서 MyWPFApp 프로젝트를 마우스 오른쪽 버튼으로 클릭하고 NuGet 패키지 관리...를 선택합니다.

    2. 찾아보기 탭의 검색 상자에 Microsoft.Toolkit.Wpf.UI.Controls를 입력하거나 붙여넣습니다. 안정적인 최신 버전을 선택하고 설치를 클릭합니다. 이 패키지는 WPF에 래핑된 UWP XAML 컨트롤(InkCanvas, InkToolbarWindowsXamlHost 컨트롤 포함)을 사용하는 데 필요한 모든 항목을 제공합니다.

    참고

    Windows Forms 앱의 경우 대신 Microsoft.Toolkit.Forms.UI.Controls 패키지를 참조하세요.

  3. 대부분의 XAML Islands 시나리오는 모든 CPU를 대상으로 하는 프로젝트에서 지원되지 않습니다. 따라서 특정 아키텍처(예: x86 또는 x64)를 대상으로 지정하려면 다음을 수행합니다.

    1. 솔루션 탐색기에서 솔루션 노드(프로젝트 노드 아님)를 마우스 오른쪽 버튼으로 클릭하고 속성을 선택합니다.
    2. 왼쪽에서 구성 속성을 선택합니다.
    3. 구성 관리자... 버튼을 클릭합니다.
    4. 활성 솔루션 플랫폼에서 새로 만들기를 선택합니다.
    5. 새 솔루션 플랫폼 대화 상자에서 x64 또는 x86을 선택하고 확인을 누릅니다.
    6. 열기 대화 상자를 닫습니다.

새 UWP 프로젝트에서 XamlApplication 클래스 정의

이 섹션에서는 UWP 프로젝트를 솔루션에 추가하고 Microsoft.Toolkit.Win32.UI.XamlHost.XamlApplication 클래스에서 파생되도록 해당 프로젝트의 기본 App 클래스를 수정합니다. 해당 클래스는 IXamlMetadataProvider 인터페이스를 지원합니다. 이 인터페이스를 통해 앱은 런타임 시 애플리케이션의 현재 디렉터리에 있는 어셈블리의 사용자 지정 UWP XAML 컨트롤에 대한 메타데이터를 검색하고 로드할 수 있습니다. 해당 클래스는 현재 스레드에 대한 UWP XAML 프레임워크도 초기화합니다.

  1. 솔루션 탐색기에서 솔루션 노드를 마우스 오른쪽 버튼으로 클릭하고 추가>새 프로젝트...를 선택합니다.

  2. C# 빈 앱(유니버설 Windows) 프로젝트 템플릿을 선택합니다. 이 토픽의 단계 또는 소스 코드를 편집할 필요가 없도록 프로젝트 이름MyUWPApp으로 설정합니다. 대상 버전최소 버전Windows 10 버전 1903(빌드 18362) 이상으로 설정합니다.

    참고

    MyWPFApp의 하위 폴더에 MyUWPApp을 만들지 않도록 합니다. 이렇게 하면 MyWPFApp이 WPF XAML인 것처럼 UWP XAML 마크업을 빌드하려고 합니다.

  3. 0MyUWPApp에서 Microsoft.Toolkit.Win32.UI.XamlApplication NuGet 패키지(안정적인 최신 버전)를 설치합니다. NuGet 패키지를 설치하는 프로세스는 이전 섹션에서 설명했습니다.

  4. MyUWPApp에서 App.xaml 파일을 열고 해당 내용을 다음 XAML로 바꿉니다.

    <xaml:XamlApplication
        x:Class="MyUWPApp.App"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:xaml="using:Microsoft.Toolkit.Win32.UI.XamlHost"
        xmlns:local="using:MyUWPApp">
    </xaml:XamlApplication>
    
  5. 마찬가지로 App.xaml.cs을(를) 열고 내용을 다음 코드로 바꿉니다.

    namespace MyUWPApp
    {
        public sealed partial class App : Microsoft.Toolkit.Win32.UI.XamlHost.XamlApplication
        {
            public App()
            {
                this.Initialize();
            }
        }
    }
    
  6. MainPage.xamlMainPage.xaml.cs 파일을 삭제합니다.

  7. MyUWPApp 프로젝트를 빌드합니다.

MyWPFApp에서 MyUWPApp 프로젝트에 대한 참조를 추가합니다.

  1. 다음과 같이 MyWPFApp의 프로젝트 파일에서 호환되는 프레임워크 버전을 지정합니다.

    1. 솔루션 탐색기에서 MyWPFApp 프로젝트 노드를 클릭하여 편집기에서 프로젝트 파일을 엽니다.

    2. 첫 번째 PropertyGroup 요소 내에서 다음 하위 요소를 추가합니다. 필요에 따라 MyWPFApp 프로젝트의 대상 및 최소 OS 빌드와 일치하도록 값의 19041 부분을 변경합니다.

      <AssetTargetFallback>uap10.0.19041</AssetTargetFallback>
      
  2. 솔루션 탐색기에서 MyWPFApp>종속성을 마우스 오른쪽 버튼으로 클릭하고, 프로젝트 참조 추가...를 선택하고, MyUWPApp 프로젝트에 대한 참조를 추가합니다.

MyWPFApp의 진입점에서 XamlApplication 개체 인스턴스화

다음으로, MyWPFApp의 진입점에 코드를 추가하여 MyUWPApp(XamlApplication에서 파생된 클래스)에서 방금 정의한 App 클래스의 인스턴스를 만듭니다.

  1. MyWPFApp 프로젝트 노드를 마우스 오른쪽 버튼으로 클릭하고 추가>새 항목...을 선택한 다음, 클래스를 선택합니다. 이름Program.cs로 설정하고 추가를 클릭합니다.

  2. Program.cs의 내용을 다음 XAML로 바꿉니다(그런 다음, 파일을 저장하고 MyWPFApp 프로젝트 빌드).

    namespace MyWPFApp
    {
        public class Program
        {
            [System.STAThreadAttribute()]
            public static void Main()
            {
                using (new MyUWPApp.App())
                {
                    var app = new MyWPFApp.App();
                    app.InitializeComponent();
                    app.Run();
                }
            }
        }
    }
    
  3. MyWPFApp 프로젝트 노드를 마우스 오른쪽 버튼으로 클릭하고 속성을 선택합니다.

  4. 애플리케이션>일반에서 Startup 개체 드롭다운을 클릭하고 MyWPFApp.Program(방금 추가한 Program 클래스의 정규화된 이름)을 선택합니다. 표시되지 않으면 Visual Studio를 닫았다가 다시 여세요.

    참고

    기본적으로 WPF 프로젝트는 수정을 의도하지 않은 생성된 코드 파일에서 Main 진입점 함수를 정의합니다. 위의 단계에서는 프로젝트에 대한 진입점을 새 Program 클래스의 Main 메서드로 변경하여 앱의 시작 프로세스 초기에 최대한 빨리 실행되는 코드를 추가할 수 있습니다.

  5. 프로젝트 속성에 대한 변경 내용을 저장하세요.

래핑된 컨트롤을 사용하여 InkCanvas 및 InkToolbar 호스트

UWP XAML Islands를 사용하도록 프로젝트를 구성했으므로, 이제 InkCanvasInkToolbar 래핑된 UWP XAML 컨트롤을 앱에 추가할 준비가 되었습니다.

  1. MyWPFApp에서 MainWindow.xaml 파일을 엽니다.

  2. XAML 파일의 위쪽에 있는 Window 요소에 다음 특성을 추가합니다. 이 특성은 InkCanvasInkToolbar 래핑된 UWP XAML 컨트롤에 대한 XAML 네임스페이스를 참조하고 컨트롤 XML 네임스페이스에 매핑합니다.

    xmlns:controls="clr-namespace:Microsoft.Toolkit.Wpf.UI.Controls;assembly=Microsoft.Toolkit.Wpf.UI.Controls"
    
  3. 여전히 MainWindow.xaml에서 아래 XAML처럼 보이도록 기존 Grid 요소를 편집합니다. 이 XAML은 GridInkCanvasInkToolbar 컨트롤을 추가합니다(이전 단계에서 정의한 컨트롤 XML 네임스페이스가 접두사로 붙음).

    <Grid Margin="10,50,10,10">
        <Grid.RowDefinitions>
            <RowDefinition Height="Auto"/>
            <RowDefinition Height="Auto"/>
        </Grid.RowDefinitions>
        <controls:InkToolbar x:Name="myInkToolbar" TargetInkCanvas="{x:Reference myInkCanvas}" Grid.Row="0" Width="300"
            Height="50" Margin="10,10,10,10" HorizontalAlignment="Left" VerticalAlignment="Top" />
        <controls:InkCanvas x:Name="myInkCanvas" Grid.Row="1" HorizontalAlignment="Left" Width="600" Height="400"
            Margin="10,10,10,10" VerticalAlignment="Top" />
    </Grid>
    

    참고

    도구 상자Windows 커뮤니티 도구 키트 섹션에서 디자이너로 끌어 이러한 컨트롤 및 기타 래핑된 컨트롤을 에 추가할 수도 있습니다.

  4. 저장 MainWindow.xaml.

    디지털 펜을 지원하는 디바이스(예: Surface)가 있고 물리적 머신을 수행하는 경우 이제 앱을 빌드 및 실행하고 펜을 사용하여 화면에 디지털 잉크를 그릴 수 있습니다. 그러나 마우스로 쓰려고 하면 기본적으로 InkCanvas가 디지털 펜에 대해서만 사용하도록 설정되므로 아무 일도 발생하지 않습니다. 마우스에 InkCanvas를 사용하도록 설정하는 방법은 다음과 같습니다.

  5. MyWPFApp에 계속 머물러 있고, MainWindow.xaml.cs을(를) 엽니다.

  6. 다음 네임스페이스 지시문을 파일의 맨 위에 추가합니다.

    using Microsoft.Toolkit.Win32.UI.Controls.Interop.WinRT;
    
  7. MainWindow 생성자를 위치시킵니다. InitializeComponent 호출 직후에 다음 코드 줄을 추가합니다.

    myInkCanvas.InkPresenter.InputDeviceTypes = CoreInputDeviceTypes.Mouse | CoreInputDeviceTypes.Pen;
    

    InkPresenter 개체를 사용하여 기본 수동 입력 환경을 사용자 지정할 수 있습니다. 위의 코드는 InputDeviceTypes 속성을 사용하여 마우스와 펜 입력을 사용하도록 설정합니다.

  8. 저장, 빌드 및 실행합니다. 컴퓨터에서 마우스를 사용하는 경우 잉크 캔버스 공간에서 마우스로 그림을 그릴 수 있는지 확인합니다.

호스트 컨트롤을 사용하여 CalendarView 호스트

이 섹션에서는 WindowsXamlHost 컨트롤을 사용하여 앱에 CalendarView를 추가합니다.

참고

WindowsXamlHost 컨트롤은 Microsoft.Toolkit.Wpf.UI.XamlHost 패키지에서 제공됩니다. 해당 패키지는 이전에 설치한 Microsoft.Toolkit.Wpf.UI.Controls 패키지에 포함되어 있습니다.

  1. 솔루션 탐색기MyWPFApp에서 MainWindow.xaml 파일을 엽니다.

  2. XAML 파일의 위쪽에 있는 Window 요소에 다음 특성을 추가합니다. 이 특성은 WindowsXamlHost 컨트롤에 대한 XAML 네임스페이스를 참조하고 xamlhost XML 네임스페이스에 매핑합니다.

    xmlns:xamlhost="clr-namespace:Microsoft.Toolkit.Wpf.UI.XamlHost;assembly=Microsoft.Toolkit.Wpf.UI.XamlHost"
    
  3. 여전히 MainWindow.xaml에서 아래 XAML처럼 보이도록 기존 Grid 요소를 편집합니다. 이 XAML은 GridWindowsXamlHost 컨트롤을 추가합니다(이전 단계에서 정의한 xamlhost XML 네임스페이스가 접두사로 붙음). UWP CalendarView 컨트롤을 호스팅하기 위해 이 XAML은 InitialTypeName 속성을 컨트롤의 정규화된 이름으로 설정합니다. 또한 XAML은 호스팅된 컨트롤이 렌더링될 때 발생하는 ChildChanged 이벤트에 대한 이벤트 처리기를 정의합니다.

    <Grid Margin="10,50,10,10">
        <xamlhost:WindowsXamlHost x:Name="myCalendar" InitialTypeName="Windows.UI.Xaml.Controls.CalendarView"
              Margin="10,10,10,10" Width="600" Height="300" ChildChanged="MyCalendar_ChildChanged" />
    </Grid>
    
  4. MainWindow.xaml을(를) 저장하고 MainWindow.xaml.cs을(를) 엽니다.

  5. 이전 섹션에서 추가한 myInkCanvas.InkPresenter.InputDeviceTypes = CoreInputDeviceTypes.Mouse | CoreInputDeviceTypes.Pen; 코드 줄을 삭제합니다.

  6. 다음 네임스페이스 지시문을 파일의 맨 위에 추가합니다.

    using Microsoft.Toolkit.Wpf.UI.XamlHost;
    
  7. MainWindow 클래스에 다음 ChildChanged 이벤트 처리기 메서드를 추가합니다. 호스트 컨트롤이 렌더링되면 이 이벤트 처리기가 실행되고, 캘린더 컨트롤의 SelectedDatesChanged 이벤트에 대한 간단한 이벤트 처리기를 만듭니다.

    private void MyCalendar_ChildChanged(object sender, EventArgs e)
    {
        WindowsXamlHost windowsXamlHost = (WindowsXamlHost)sender;
    
        var calendarView =
            (Windows.UI.Xaml.Controls.CalendarView)windowsXamlHost.Child;
    
        if (calendarView != null)
        {
            calendarView.SelectedDatesChanged += (obj, args) =>
            {
                if (args.AddedDates.Count > 0)
                {
                    MessageBox.Show("The user selected a new date: " +
                        args.AddedDates[0].DateTime.ToString());
                }
            };
        }
    }
    
  8. 저장, 빌드 및 실행합니다. 캘린더 컨트롤이 창에 표시되고 날짜를 선택할 때 메시지 상자가 표시되는지 확인합니다.

앱 패키징

필요에 따라 배포를 위해 MSIX 패키지에 WPF 앱을 패키징할 수 있습니다. MSIX는 Windows를 위한 최신의 안정적인 앱 패키징 기술입니다.

다음 지침에서는 Visual Studio에서 Windows 애플리케이션 패키징 프로젝트를 사용하여 솔루션의 모든 구성 요소를 MSIX 패키지로 패키징하는 방법을 보여줍니다(Visual Studio에서 MSIX 패키징에 대한 데스크톱 응용 프로그램 설정 참조). 이러한 단계는 MSIX 패키지에서 WPF 앱을 패키징하는 경우에만 필요합니다.

참고

배포를 위해 MSIX 패키지로 애플리케이션을 패키징하지 않도록 선택하는 경우 앱을 실행하는 컴퓨터에 Visual C++ Runtime이 설치되어 있어야 합니다.

  1. Windows 애플리케이션 패키징 프로젝트의 프로젝트 템플릿에서 만든 솔루션에 새 프로젝트를 추가합니다. 프로젝트를 만들 때 UWP 프로젝트에 대해 선택한 것과 동일한 대상 버전최소 버전을 선택합니다.

  2. 패키징 프로젝트에서 종속성 노드를 마우스 오른쪽 버튼으로 클릭하고 프로젝트 참조 추가...를 선택합니다. 프로젝트 목록에서 MyWPFApp을 선택하고 확인을 클릭합니다.

    참고

    Microsoft Store에 앱을 게시하려면 패키징 프로젝트에서 UWP 프로젝트에 대한 참조도 추가해야 합니다.

  3. 이 시점까지 단계를 수행한 경우 솔루션의 모든 프로젝트는 동일한 특정 플랫폼(x86 또는 x64)을 대상으로 합니다. Windows 애플리케이션 패키징 프로젝트를 사용하여 MSIX 패키지로 WPF 앱을 빌드하는 데 필요합니다. 이를 확인하려면 다음 단계를 수행하면 됩니다.

    1. 솔루션 탐색기에서 솔루션 노드(프로젝트 노드 아님)를 마우스 오른쪽 버튼으로 클릭하고 속성을 선택합니다.
    2. 왼쪽에서 구성 속성을 선택합니다.
    3. 구성 관리자... 버튼을 클릭합니다.
    4. 나열된 모든 프로젝트가 플랫폼: x86 또는 x64에서 동일한 값을 갖는지 확인합니다.
  4. 방금 추가한 패키징 프로젝트의 프로젝트 노드를 마우스 오른쪽 버튼으로 클릭하고 Startup 프로젝트로 설정을 클릭합니다.

  5. 패키징 프로젝트를 빌드하고 실행합니다. WPF 앱이 실행되고 UWP 컨트롤이 예상대로 표시되는지 확인합니다.

  6. 패키지 분산/배포에 대한 자세한 내용은 MSIX 배포 관리를 참조하세요.