WinUI 3 Preview 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 package, effectively allowing developers to support new features of XAML on older versions of Windows 10 without the need of end-users to upgrade their OS. Instead of relying on the XAML bits being shipped on the OS, the WinUI team literally refactored the whole XAML source code to ship it as a simple NuGet package. You can see the latest road map here. This work has been happening for a while now, with new bits being released every few months.
Since the Windows 8.x era, Microsoft has been evolving the UWP XAML framework to support new form factors and different hardware, like touch screen devices and pen enabled screens. It also provides the best-in-class native support allowing developers to leverage it through both .NET and C++ applications. However, since the UWP APIs and the XAML UI framework have been extremely tied together there has been no way to leverage the new UI improvements from a Win32 application. At least until XAML Islands was released, back in 2018, where Microsoft enabled Win32 developers to also leverage the UWP XAML technology. WinUI 3 can also be leveraged in a similar way, through a technology we’ll talk about in this article called WinUI Desktop.
Native Windows Apps
The first thing to note is that UWP applications and Win32 applications (either .NET or C++) are both native Windows applications, and they are both supported by Microsoft. They fill different needs for different applications and end users. You can’t build an Xbox app with Win32, as UWPs fill that role, and you can’t build a Windows driver with UWP. Each process execution model has its own role and place in the Windows ecosystem, and they complement each other.
UWP apps run inside a sandbox that keeps you from having access to the whole operating system as you mostly can through Win32 APIs, and these Win32 APIs exist since 1985 (Windows 1.0). Yes, Microsoft still support those same APIs. And it’s not because it’s an old ~~tech~~ process execution model that it needs to use an old UI framework. That is the beauty of WinUI Desktop. You can leverage the latest and greatest native UI stack on our oldest process execution model, which gives you more flexibility for creating your applications. Within this blog post, we’ll build a WinUI Desktop app using C#, .NET5 and WinUI3 Preview 3.
Important! This WinUI 3 preview release is intended for early evaluation and to gather feedback from the developer community. It should NOT be used for production apps.
Microsoft will continue shipping preview releases of WinUI 3 throughout 2020 and into 2021, after which the first official release will be made available.
Please use the WinUI GitHub repo to provide feedback and log suggestions and issues.
Another interesting step towards decoupling the XAML UI framework from the Windows OS is how you access those APIs, specially through managed languages, like C#. The Windows SDK is mostly written in C++ and, as I’ve mentioned before, you can use the Windows SDK from mostly any language. This interop works through an abstraction layer called Windows Runtime (WinRT), which is basically the evolution of COM, and a matching projection for each specific language. C++ developers already have a projection to access those APIs through a thing called C++/WinRT. C# developers had that as well, but it was embedded inside the UWP C# compiler and runtime (and was removed in .NET 5). This is where the C#/WinRT project comes. It provides the WinRT projections for C#, hiding the details of the interop between C# and WinRT, and is shipped as a simple NuGet package, completely decoupled from the Windows SDK.
By lifting this projection out of the compiler and the runtime Microsoft is enabling the use of .NET5 with XAML applications. For most developers, C#/WinRT is an implementation detail and won’t affect you much, but if you are authoring a library, it is important to understand how to provide these projections alongside your existing DLLs/WinMDs. This is a breaking change from an authoring perspective of .NET Core 3.1, so if that affects you, take a moment to read through the docs to provide these projections for your library. There is also a very good blog post about C#/WinRT.
WinUI Desktop basics
Now that you know the theory, let’s actually use WinUI 3.0.0-preview3 in a simple Win32/Desktop application. You need VS 2019 16.9 Preview1+, and the Visual Studio templates for WinUI 3.0.0-preview3. You can see all requirements here.
Once in VS Preview with the templates installed, simply create a new WinUI Desktop project:
Give the project a name, a location, and select the min version of Windows where you want your application to be supported. That is actually one of WinUI3’s benefits. Since anything from the MUX (Microsoft.UI.Xaml.*) namespace is lifted from the OS, you know that it will be available wherever your app is running. There is no need to specify a newer minimum OS version to use a newer XAML API, which simplifies your development, without the need to check for XAML APIs availability. Conditional XAML, for purely accessing newer XAML APIs that were not available on older OS versions, is pretty much obsolete with WinUI3. You might still want to use it for showing different UIs for, let’s say, only show a “Connect Bluetooth LE 5 device” button on an newer OS version that has Bluetooth LE 5 support, since only XAML related APIs are lifted on WinUI3, but for anything from XAML itself, you can freely call any API and it should be available at all OS versions where WinUI3 is supported.
Since I’m not using any API that is particularly new, I’ve selected the oldest version where WinUI3 runs on as the minimum version, which is 1803.
Now that the solution and its projects are created, let’s take a quick look at how this template initiates our project.
We don’t see a single project, but two projects. That is due to the fact that WinUI3, as of preview3, requires an App ID to run, and since WinUI Desktop is a Win32 application (which doesn’t have an App Id by default), we need to provide this somehow. The correct solution to this problem is packaging the Win32 project through a Packaging project (MSIX), which is what the “WinUI3Preview3Sample (Package)” project is. It simply references the main Win32 project and adds an AppXManifest file.
The structure of our main WinUI Desktop project is very familiar to any UWP developer. You have an
App.xaml.cs file, and a
Main*Something*.xaml.cs file. In UWP, this
*Something* was a Page. In WinUI Desktop, this
*Something* is a new concept called Window, similar to WPF’s Window. Inside
App.xaml, we have a simple initialization of WinUI’s Resource Dictionary, as any UWP with WinUI2 app needs to do today.
Our App.xaml.cs, on the other hand, is slightly different and simpler from our UWP counterpart:
We only need to instantiate our
MainWindow class and call it’s
Activate method. This loads the main window and shows it to the user.
This is our simple Window’s Xaml implementation:
We have a simple StackPanel and a button inside it. Clicking on the button triggers the myButton_Click event, that exists in our MainWindow.xaml.cs file:
And the only thing that this simple code does is change the button’s Content (e.g. its text) to “Clicked”.
Now that we know how our project is structured, let’s run it! This should be as simple as selecting the right platform and pressing F5 to build, run, and see the magic happen:
It will build and pack your Win32 app inside the packaging project, and automatically install it in your system.
And when you click on the button:
Very simple app, but we can evolve from here. Instead of changing the button’s text to “Clicked”, let’s prove that this is a Win32 app. Let’s call a user32.dll method directly into this window’s HWND. Fun!
I’ve chosen a very simple Win32 API called
SetWindowPos which enables me to, for example, move the window around. But before we can call this API, we need to take a hold of this window’s HWND, which is not that simple. The window from a WinUI Desktop app implements an interface that contains a reference to this HWND, but its not exposed publicly by WinUI’s API layer for us to use. Luckily, C#/WinRT can help! We just need to know which interface that class is implementing internally, and ask C#/WinRT to give us a representation of this object as an object that implements this interface. The hard part is to know/provide the right interface. Once we have that, we call the
.As<T>() method from C#/WinRT and get the property that contains that HWND, with which we can do pretty much anything with.
And just like that, if you run your app again, when you click on the button, it will move the window around! Isn’t that amazing? I just love when we mix the old and the new in a seamless way. The possibilities are endless! You can even use the Windows Community Toolkit, which has a preview version that supports WinU3!
That was our first WinUI Desktop app. Its a simple one, but you can see how we can easily leverage the amazing Windows UI stack from a Win32 application with a straight-forward Visual Studio template. Now its your time to create beautiful, complex, fully-featured applications with WinUI Desktop.
Checkout the source of the code of the sample shared here.
We welcome your feedback in the WinUI GitHub repo.