If you look at what Microsoft is working on with Project Reunion, it’s clear to see that they’ve set a vision to reunite the various groups of Windows developers. The aim is not to have every developer using exactly the same technology stack but rather to give every developer access to the richness of the Windows platform, regardless of the stack that they’re using. It shouldn’t matter whether you’re building a WinForms or a WPF application, you should be able to access the same platform features that someone building a greenfield Project Reunion application does. It smells like Project Reunion is becoming the next generation of SDK for app developers targeting the Windows platform. This is all well and good but if you look at the roadmap and what the team is shipping there’s a bit of an elephant in the room – everything is focused on Windows desktop application; there’s no support for apps that want to run on Xbox, Hololens and Windows 10X. In this post we’ll look at how you can run your application on these platforms leveraging the Uno platform but I have to warn you, it’s not all that pretty.
Question: How can I run a Windows UI 3 / Project Reunion application on Windows 10x, Xbox or Hololens
Answer: You can’t run a Project Reunion (aka Windows UI 3) application on Xbox, Hololens or Windows 10X, because they’re not able to run Win32 (aka Desktop) applications.
How To – the Long Answer
Ok, so I didn’t drag you all the way to my blog post only to tell you what you had probably already read on Microsoft’s documentation. Whilst it’s not possible to simply run a Project Reunion application on these platforms, you can reuse a large portion of your code via a shared project.
As I’ve already touched on in my post, How to Upgrade a UWP Application to WinUI 3.0, it’s possible to have an application that has both a UWP and WinUI3 (Project Reunion) head project. The UWP application makes use of WinUI 2.x and you have to do a bunch of #if statements to switch namespaces between UWP and WinUI3. As I said in the introduction, it isn’t pretty or elegant but it’ll work and it’ll mean that you can continue to target UWP.
Show me!
For this we’re going to actually start with the Uno platform dotnet new template – Uno already uses the approach of having a shared project that contains all your XAML and C# code for your application, coupled with head, or target, projects for each platform you want to support. Once you’ve installed the templates, you can create a new Uno + WinUI3 application using the following dotnet new command (“unoapp-winui” is the name of the template, “nonwin32platforms” is the name you want to give the solution)
dotnet new unoapp-winui -o nonwin32platforms
As always, after creating a new solution, make sure you it builds and runs before proceeding – nothing worse than getting further down the line, only to realize that the initial solution wasn’t created properly.
Note: If you run into issues creating, or opening, the solution and you have one of the .NET 6 previews installed, I recommend creating a global.json file in the folder where you want to create the solution with the following content – this ensures the .NET 5 SDK is used by dotnet new and by Visual Studio when you launch the solution.
{
"sdk": {
"version": "5.0.201"
}
}
Next, we’re going to add the UWP target project – Right-click on the Solution node in Solution Explorer and select Add, New Project. Pick the “Blank App (Universal Windows)” project template; give the new project a name, nonwin32platforms.UWP; pick target and minimum Windows OS version and click OK. One thing to note is that the Uno template currently creates a UWP project, even though it’s not included in the solution. I’d recommend deleting this existing project as it doesn’t work – I’m sure the intent is that this will be either removed or fixed at a later stage.
The first thing we need to do with our UWP project is to add some NuGet packages (just pick the latest stable releases): Microsoft.UI.Xaml (aka WinUI2.x), Uno.Core, Microsoft.Extensions.Logging.Console
Next, add a reference to the shared project, which in this case is called nonwin32platforms.Shared. You’ll also need to delete the existing App.xaml (and App.xaml.cs) and MainPage.xaml (and MainPage.xaml.cs) from the UWP project to avoid having duplicates.
Make sure the UWP project is set to build and deploy in the Configuration Manager.
At this point if you attempt to build your UWP project you’ll see a bunch of build errors because the namespace Microsoft.UI.Xaml doesn’t exist. This is where we need to use #if conditions to control which namespaces are imported. In order to do this we need to specify a compilation constant that will define whether the code is being built for UWP or for WinUI. Luckily, the UWP project already has a constant, WINDOWS_UWP, which can be used to determine if the code is being compiled for UWP. We can update the using statements as follows (for both App.xaml.cs and MainPage.xaml.cs):
#if WINDOWS_UWP
using Windows.ApplicationModel.Activation;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
using Windows.UI.Xaml.Controls.Primitives;
using Windows.UI.Xaml.Data;
using Windows.UI.Xaml.Input;
using Windows.UI.Xaml.Media;
using Windows.UI.Xaml.Navigation;
#else
using Microsoft.UI.Xaml;
using Microsoft.UI.Xaml.Controls;
using Microsoft.UI.Xaml.Controls.Primitives;
using Microsoft.UI.Xaml.Data;
using Microsoft.UI.Xaml.Input;
using Microsoft.UI.Xaml.Media;
using Microsoft.UI.Xaml.Navigation;
#endif
Remove any fully qualified namespaces that start with Microsoft.UI.Xaml, instead rely on the using statement to import the namespace.
There are a couple of other build errors relating to code in App.xaml.cs that either need to be commented out, or the WINDOWS_UWP constant needs to be used. For example
#if (WINDOWS_UWP)
if (e.PrelaunchActivated == false)
#elif !(NET5_0 && WINDOWS)
if (e.UWPLaunchActivatedEventArgs.PrelaunchActivated == false)
#endif
And that’s it – you should be good to build and run your UWP application. Of course, as you build out your application you’ll need to continue to test to make sure your code is compatible with both your WinUI targets and your UWP target.
Thank you Nick,
I just started to work on Hololens at work and I really appreciate this publication.
I find it very useful information.
Although I decided to go with UWP because is should be more mature than WinUI, I kept a bookmark on this.
Please note: I feel that doing UWP and/or WinGui3 makes me partly go 25 years ago… I feel going back to the dinosaur ages when I was forced to use win32 api from C++ or VB. There is still nothing to get Desktop workarea rect and or taskbar info, nothing to position a Top level window where we want on the desktop. Sometimes Microsoft really sucks. The support many frameworks and langages but none of them is complete. No vision, no leader, very bad gestion. I hope it will change…
Hi Eric,
I think the new windowing support coming in winui will address some of your points about positioning top level window. I can’t disagree with regards to the vision.