티스토리 뷰

.NET 5 and .NET Conf 2020

WinUI 3 Preview 3

Connor Park 2021. 1. 8. 14:36

 

2021년에 WinUI3.0이 정식 릴리즈 될 예정인데, 제가 한번도 포스팅을 않했던 것 같습니다. 이 포스팅을 참고하시면 대략적인 내용을 아실 수 있을 것 같습니다.

 

WinUI 3 Preview 3 | Windows Dev (microsoft.com)

 

WinUI 3 Preview 3 | Windows Dev

WinUI 3 At Ignite 2019 Microsoft released the first bits of Windows UI Library (WinUI) version 3 (a.k.a. WinUI 3), an evolution of the UWP/XAML platform, that decouples the XAML UI framework from the Windows OS. It is shipped in its whole as a NuGet packag

devblogs.microsoft.com

 

Ignite 2019에서 Microsoft는 Windows OS에서 XAML UI 프레임 워크를 분리하는 UWP/XAML 플랫폼의 진화인 Windows UI Library (WinUI) version 3.0 (일명 WinUI 3)의 첫 번째 비트를 출시했습니다. 전체가 NuGet 패키지로 제공되므로 개발자는 최종 사용자가 OS를 업그레이드 할 필요없이 이전 버전의 Windows 10에서 XAML의 새로운 기능을 효과적으로 지원할 수 있습니다. OS에서 제공되는 XAML 비트에 의존하는 대신 WinUI 팀은 전체 XAML 소스 코드를 리팩터링하여 간단한 NuGet 패키지로 제공했습니다. 여기에서 최신 로드맵을 볼 수 있습니다. 이 작업은 몇 달에 한 번씩 새로운 비트가 출시되면서 한동안 진행되고 있습니다.

 

Windows 8.x 시대부터 Microsoft는 터치 스크린 장치 및 펜 사용 화면과 같은 새로운 폼 팩터 및 다양한 하드웨어를 지원하도록 UWP XAML 프레임 워크를 발전시켜 왔습니다. 또한 개발자가 .NET 및 C ++ 응용 프로그램을 통해이를 활용할 수 있도록 동급 최고의 기본 지원을 제공합니다. 그러나 UWP API와 XAML UI 프레임 워크가 매우 밀접하게 연결되어 있기 때문에 Win32 응용 프로그램에서는 새로운 UI 개선 사항을 활용할 방법이 없었습니다. Microsoft는 2018년에 XAML Islands가 출시되 Win32(WPF) 개발자가 UWP XAML 기술을 활용할 수 있도록 했습니다. 여기서 이야기하는 WinUI 3은 WinUI Desktop이라는 기술을 통해 WPF, UWP에서 모두 사용 가능한 컨트롤을 만들었습니다.

Native Windows Apps

가장 먼저 주목할 점은 UWP 애플리케이션과 Win32 애플리케이션 (.NET 또는 C ++)이 모두 기본 Windows 애플리케이션이며 둘 다 Microsoft에서 지원한다는 것입니다. 다양한 애플리케이션과 최종 사용자의 다양한 요구 사항을 충족해야 합니다. Win32로 Xbox 앱을 빌드 할 수 없으며 UWP로 Windows 드라이버를 빌드 할 수 없습니다. 각 프로세스 실행 모델은 Windows 에코 시스템에서 고유 한 역할과 위치를 가지며 서로를 보완합니다.

 

UWP 앱은 대부분 Win32 API를 통해 할 수있는 것처럼 전체 운영 체제에 액세스 할 수 없도록하는 샌드 박스 내에서 실행되며 이러한 Win32 API는 1985 (Windows 1.0) 이후 존재합니다. 예, Microsoft는 여전히 동일한 API를 지원합니다. 그리고 그것은 오래된 UI 프레임 워크를 사용해야하는 오래된 ~~ 기술 ~~ 프로세스 실행 모델이기 때문이 아닙니다. 이것이 WinUI Desktop의 아름다움입니다. 가장 오래된 프로세스 실행 모델에서 가장 뛰어난 최신 네이티브 UI 스택을 활용할 수 있으므로 애플리케이션 생성에 더 많은 유연성을 제공합니다. 이 블로그 게시물에서는 C#, .NET5 및 WinUI3 Preview 3을 사용하여 WinUI Desktop 앱을 빌드 할 것입니다.

 

중요! 이 WinUI 3 미리보기 릴리스는 초기 평가 및 개발자 커뮤니티의 피드백을 수집하기위한 것입니다. 프로덕션 앱에는 사용하면 안됩니다.

Microsoft는 2020 년과 2021 년까지 WinUI 3의 미리보기 릴리스를 계속 제공 할 것이며, 그 후 첫 번째 공식 릴리스를 사용할 수 있습니다.

피드백을 제공하고 제안 및 문제를 기록하려면 WinUI GitHub 리포지토리를 사용하십시오.

C#/WinRT

Windows OS에서 XAML UI 프레임 워크를 분리하는 또 다른 흥미로운 단계는 특히 C#과 같은 관리 언어를 통해 해당 API에 액세스하는 방법입니다. Windows SDK는 대부분 C++로 작성되었으며 앞서 언급했듯이 대부분의 언어에서 Windows SDK를 사용할 수 있습니다. 이 interop은 기본적으로 COM의 진화인 WinRT (Windows 런타임)라는 추상화 계층과 각 특정 언어에 대한 일치 프로젝션을 통해 작동합니다. C++ 개발자는 이미 C++/WinRT라는 것을 통해 이러한 API에 액세스 할 수있는 프로젝션을 가지고 있습니다. C# 개발자도이 기능을 가지고 있었지만 UWP C# 컴파일러 및 런타임에 포함되었습니다 (.NET 5에서 제거됨). 이것이 C#/WinRT 프로젝트가 나오는 곳입니다. C#에 대한 WinRT 프로젝션을 제공하고 C#과 WinRT 간의 상호 운용에 대한 세부 정보를 숨기고 Windows SDK에서 완전히 분리 된 간단한 NuGet 패키지로 제공됩니다.

 

이 프로젝션을 컴파일러 및 런타임에서 제거함으로써 Microsoft는 XAML 응용 프로그램에서 .NET5를 사용할 수 있습니다. 대부분의 개발자에게 C#/WinRT는 구현 세부 사항이며 많은 영향을 미치지 않지만 라이브러리를 작성하는 경우 기존 DLL/WinMD와 함께 이러한 프로젝션을 제공하는 방법을 이해하는 것이 중요합니다. 이는 .NET Core 3.1의 작성 관점에서 획기적인 변경 사항이므로 영향을받는 경우 잠시 시간을내어 라이브러리에 대한 이러한 프로젝션을 제공하기 위해 문서를 읽어보십시오. C#/WinRT에 대한 매우 좋은 블로그 게시물도 있습니다.

 

WinUI3 Desktop basics

이론을 알았으니 이제 간단한 Win32/Desktop 애플리케이션에서 WinUI 3.0.0-preview3를 실제로 사용해 보겠습니다. Visual Studio 2019 16.9 Preview1+WinUI 3.0.0-preview3 용 Visual Studio 템플릿이 필요합니다. 여기에서 모든 요구 사항을 확인할 수 있습니다.

 

Visual Studio 2019 16.8.3 버전에서도 Extension 설치 후 생성이 가능합니다.

 


템플릿이 설치된 VS Preview에서 새 WinUI Desktop 프로젝트를 만들기 만하면됩니다.

Blank App, Packaged (WinUI in Desktop)

프로젝트에 이름과 위치를 지정하고 애플리케이션을 지원할 최소 Windows 버전을 선택합니다. 이것은 실제로 WinUI3의 이점 중 하나입니다. MUX (Microsoft.UI.Xaml. *) 네임 스페이스의 모든 것이 OS에서 해제되었으므로 앱이 실행되는 모든 곳에서 사용할 수 있습니다. 새로운 XAML API를 사용하기 위해 새로운 최소 OS 버전을 지정할 필요가 없습니다. 이는 XAML API 가용성을 확인할 필요없이 개발을 단순화합니다. 이전 OS 버전에서 사용할 수 없었던 최신 XAML API에 순수하게 액세스하기위한 조건부 XAML은 WinUI3에서 거의 사용되지 않습니다. WinUI3에서는 XAML 관련 API 만 해제되기 때문에 Bluetooth LE 5를 지원하는 최신 OS 버전에서 "Bluetooth LE 5 장치 연결"단추 만 표시하는 것과 같이 다른 UI를 표시하는 데 계속 사용할 수 있습니다. XAML 자체에서 모든 API를 자유롭게 호출 할 수 있으며 WinUI3가 지원되는 모든 OS 버전에서 사용할 수 있어야합니다.

특히 새로운 API를 사용하지 않기 때문에 WinUI3가 실행되는 가장 오래된 버전 인 1803을 최소 버전으로 선택했습니다.


이제 솔루션과 해당 프로젝트가 생성되었으므로이 템플릿이 프로젝트를 시작하는 방법을 간단히 살펴 보겠습니다.

하나의 프로젝트가 아니라 두 개의 프로젝트가 표시됩니다. 이는 preview3에서 WinUI3를 실행하려면 앱 ID가 필요하고 WinUI Desktop이 Win32 애플리케이션 (기본적으로 앱 ID가 없음)이므로 어떻게 든 제공해야하기 때문입니다. 이 문제에 대한 올바른 해결책은 패키징 프로젝트 (MSIX)를 통해 Win32 프로젝트를 패키징하는 것입니다. 이것이 "WinUI3Preview3Sample (패키지)"프로젝트입니다. 단순히 주 Win32 프로젝트를 참조하고 AppXManifest 파일을 추가합니다.

 

주 WinUI Desktop 프로젝트의 구조는 모든 UWP 개발자에게 매우 친숙합니다. App.xaml/App.xaml.cs 파일과 Main*Something*.xaml/Main*Something*.xaml.cs 파일이 있습니다. UWP에서 이 *Something*은 페이지였습니다. WinUI Desktop에서이 *Something*은 WPF의 Window와 유사한 Window라는 새로운 개념입니다. App.xaml 내부에는 WinUI2 앱이있는 모든 UWP가 오늘날 수행해야하는 것처럼 WinUI 리소스 사전의 간단한 초기화가 있습니다.

<!--App.xaml-->

<Application
    x:Class="WinUI3Preview3Sample.App"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="using:WinUI3Preview3Sample">
    <Application.Resources>
        <ResourceDictionary>
            <ResourceDictionary.MergedDictionaries>
                <XamlControlsResources xmlns="using:Microsoft.UI.Xaml.Controls" />
                <!-- Other merged dictionaries here -->
            </ResourceDictionary.MergedDictionaries>
            <!-- Other app resources here -->
        </ResourceDictionary>
    </Application.Resources>
</Application>

반면에 App.xaml.cs는 UWP와 약간 다르고 간단합니다.

//App.xaml.cs

using Microsoft.UI.Xaml;
using Windows.ApplicationModel;

// To learn more about WinUI, the WinUI project structure,
// and more about our project templates, see: http://aka.ms/winui-project-info.

namespace WinUI3Preview3Sample
{
    /// <summary>
    /// Provides application-specific behavior to supplement the default Application class.
    /// </summary>
    public partial class App : Application
    {
        /// <summary>
        /// Initializes the singleton application object.  This is the first line of authored code
        /// executed, and as such is the logical equivalent of main() or WinMain().
        /// </summary>
        public App()
        {
            this.InitializeComponent();
            this.Suspending += OnSuspending;
        }

        /// <summary>
        /// Invoked when the application is launched normally by the end user.  Other entry points
        /// will be used such as when the application is launched to open a specific file.
        /// </summary>
        /// <param name="args">Details about the launch request and process.</param>
        protected override void OnLaunched(Microsoft.UI.Xaml.LaunchActivatedEventArgs args)
        {
            m_window = new MainWindow();
            m_window.Activate();
        }

        /// <summary>
        /// Invoked when application execution is being suspended.  Application state is saved
        /// without knowing whether the application will be terminated or resumed with the contents
        /// of memory still intact.
        /// </summary>
        /// <param name="sender">The source of the suspend request.</param>
        /// <param name="e">Details about the suspend request.</param>
        private void OnSuspending(object sender, SuspendingEventArgs e)
        {
            // Save application state and stop any background activity
        }

        private Window m_window;
    }
}

MainWindow 클래스를 인스턴스화하고 Activate 메서드를 호출하기 만하면됩니다. 이렇게하면 기본 창이로드되고 사용자에게 표시됩니다.

 

다음은 간단한 Window의 Xaml 구현입니다.

<!--MainWindow.xaml-->

<Window
    x:Class="WinUI3Preview3Sample.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="using:WinUI3Preview3Sample"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    mc:Ignorable="d">

    <StackPanel Orientation="Horizontal" HorizontalAlignment="Center" VerticalAlignment="Center">
        <Button x:Name="myButton" Click="myButton_Click">Click Me</Button>
    </StackPanel>
</Window>

간단한 StackPanel과 그 안에 버튼이 있습니다. 버튼을 클릭하면 MainWindow.xaml.cs 파일에있는 myButton_Click 이벤트가 트리거됩니다.

//MainWindow.xaml.cs

using Microsoft.UI.Xaml;

// To learn more about WinUI, the WinUI project structure,
// and more about our project templates, see: http://aka.ms/winui-project-info.

namespace WinUI3Preview3Sample
{
    /// <summary>
    /// An empty window that can be used on its own or navigated to within a Frame.
    /// </summary>
    public sealed partial class MainWindow : Window
    {
        public MainWindow()
        {
            this.InitializeComponent();
        }

        private void myButton_Click(object sender, RoutedEventArgs e)
        {
            myButton.Content = "Clicked";
        }
    }
}

이 간단한 코드가 수행하는 유일한 작업은 버튼의 콘텐츠 (예 : 텍스트)를 "Clicked"으로 변경하는 것입니다.

이제 프로젝트가 어떻게 구성되었는지 알았으니 실행 해 보겠습니다! 이는 올바른 플랫폼을 선택하고 F5 키를 눌러 빌드, 실행 및 마법이 일어나는 것처럼 간단해야합니다.

패키징 프로젝트 내에서 Win32 앱을 빌드하고 패키징하고 자동으로 시스템에 설치합니다.

그리고, 버튼을 클릭하면

매우 간단한 앱이지만 여기서부터 발전 할 수 있습니다. 버튼의 텍스트를 "Clicked"로 변경하는 대신 이것이 Win32 앱임을 증명해 보겠습니다. 이 창의 HWND에 직접 user32.dll 메서드를 호출 해 보겠습니다.

 

예를 들어 창을 이동할 수있는 SetWindowPos라는 매우 간단한 Win32 API를 선택했습니다. 그러나 이 API를 호출하기 전에 이 창의 HWND를 파악해야합니다. 이는 그렇게 간단하지 않습니다. WinUI3 데스크톱 앱의 창은 이 HWND에 대한 참조를 포함하는 인터페이스를 구현하지만 WinUI의 API 레이어에서 공개적으로 사용하지 않습니다. 다행히 C#/WinRT가 도움이 될 수 있습니다! 클래스가 내부적으로 구현하는 인터페이스를 알고, C#/WinRT에이 인터페이스를 구현하는 개체로이 개체의 표현을 제공하도록 요청하면됩니다. 어려운 부분은 올바른 인터페이스를 알고 / 제공하는 것입니다. 그런 다음 C#/WinRT에서 .As<T>() 메서드를 호출하고 해당 HWND를 포함하는 속성을 가져 와서 거의 모든 작업을 수행 할 수 있습니다.

using Microsoft.UI.Xaml;
using System;
using System.Runtime.InteropServices;
using WinRT;

// To learn more about WinUI, the WinUI project structure,
// and more about our project templates, see: http://aka.ms/winui-project-info.

namespace WinUI3Preview3Sample
{
    /// <summary>
    /// An empty window that can be used on its own or navigated to within a Frame.
    /// </summary>
    public sealed partial class MainWindow : Window
    {
        [DllImport("user32.dll", SetLastError = true)]
        public static extern bool SetWindowPos(IntPtr hWnd, IntPtr hWndInsertAfter, int X, int Y, int cx, int cy, int uFlags);

        [ComImport]
        [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
        [Guid("EECDBF0E-BAE9-4CB6-A68E-9598E1CB57BB")]
        internal interface IWindowNative
        {
            IntPtr WindowHandle { get; }
        }

        // Random generator
        private Random _random = new Random();

        // Handle for internal IWindownative
        private IWindowNative _windowNative;

        public MainWindow()
        {
            this.InitializeComponent();

            _windowNative = this.As<IWindowNative>();
        }

        private void myButton_Click(object sender, RoutedEventArgs e)
        {
            // Randomizes x and y position
            int x = _random.Next(1000);
            int y = _random.Next(1000);

            int HWND_TOP = 0;
            int SWP_NOSIZE = 0x0001;
            // Moves the window
            SetWindowPos(_windowNative.WindowHandle, (IntPtr)HWND_TOP, x, y, 0, 0, SWP_NOSIZE);
        }
    }
}

그리고 마찬가지로 앱을 다시 실행하고, 버튼을 클릭하면 창이 이동합니다! 놀랍지 않나요? 나는 우리가 오래된 것과 새로운 것을 매끄럽게 섞을 때를 좋아합니다. 가능성은 무한합니다! WinUI3를 지원하는 미리보기 버전이있는 Windows Community Toolkit을 사용할 수도 있습니다!

Wrapping up

이것이 우리의 첫 번째 WinUI 데스크톱 앱이었습니다. 간단하지만 Visual Studio 템플릿을 사용하여 Win32 응용 프로그램에서 놀라운 Windows UI 스택을 쉽게 활용할 수있는 방법을 알 수 있습니다. 이제 WinUI3 Desktop을 사용하여 아름답고 복잡한 모든 기능을 갖춘 응용 프로그램을 만들 시간입니다.

 

여기에서 공유 된 샘플 코드의 소스를 확인하세요.

'.NET 5 and .NET Conf 2020' 카테고리의 다른 글

.NET Conf 2021 x Seoul  (0) 2021.01.17
Xamarin.Forms 5.0 릴리즈!  (0) 2021.01.14
WinUI 3 Preview 3  (2) 2021.01.08
The future of .NET Standard  (0) 2021.01.04
What’s new in Windows Forms runtime in .NET 5.0  (0) 2020.12.23
MVVM Toolkit 사용 가이드  (0) 2020.12.06
댓글
  • 프로필사진 c00012 이 프로젝트는 지금 16.9 preview 버전에서만 제대로 작동하는 건가요? 2021.01.20 13:25
  • 프로필사진 Connor Park 위에 링크에있는 소스로 작업하지 마시고, 직접 만들어 보시는 것을 추천합니다.
    저는 Visual Studio 2019 16.8.3에서 직접 만들고 실행했습니다.
    2021.01.21 06:30 신고
댓글쓰기 폼