.NET MAUI, UWP & Other Options

This content was generated with the assistance of AI and should be verified against the official documentation before being relied on in production; see the section bibliography for the reference material consulted while preparing these pages.

The other pages of this section teach one native Windows stack at a time. This page is about everything else on the list in the Windows developer FAQ: the cross-platform framework .NET MAUI, the hybrid web route through Blazor, the UWP platform that is now in maintenance, the Win32 and C++ route, React Native for Windows, progressive web apps, and two third-party frameworks. The aim is to say precisely what each one is, how it relates to the others (most of them end up on WinUI 3 or on Win32), what the Windows-specific parts of a project look like, and when it is the right call.

The page was written against these versions, current in October 2026:

  • .NET 10 LTS, latest patch 10.0.13, supported until 14 November 2028, with C# 14. .NET 8 and .NET 9 end support on 10 November 2026.

  • .NET 11 at release candidate 2. Its MAUI documentation exists (the net-maui-11.0 moniker); this page notes where it differs and otherwise describes .NET 10.

  • Visual Studio 2026, latest 18.11.1.

  • Windows App SDK 2.5.1 (stable channel), which is what .NET MAUI’s Windows head and WinUI 3 apps run on.

  • CommunityToolkit.Mvvm 8.4.2 for the view models, which the MAUI examples reuse unchanged.

  • Windows 11 and Windows 10. .NET MAUI documents Windows 11 and Windows 10 version 1809 or higher as its Windows floor; Windows 10 itself left support on 14 October 2025.

Everything that is not a Microsoft-documented route (Avalonia, Uno Platform) is labelled third-party and described in prose only. The Microsoft routes are covered with the sources they derive from; the places where the official documentation is thin are listed near the end.

The Map of Routes

Five of the routes in this page share one fact: on Windows they are not separate platforms but different ways of reaching the same two lower layers. .NET MAUI renders through WinUI 3. A Blazor Hybrid app renders HTML in a WebView2 control. UWP uses the Windows Runtime directly. Win32 and C++/WinRT are those lower layers. React Native for Windows draws native Windows UI. PWAs live in the browser engine.

flowchart TD A["Your code"] --> M[".NET MAUI - C# and XAML"] A --> B["Blazor Hybrid - Razor and C#"] A --> U["UWP - Windows.UI.Xaml"] A --> R["React Native for Windows - JavaScript and TypeScript"] A --> P["PWA - HTML, CSS, JavaScript"] A --> W["Win32 or C++/WinRT - native C++"] M --> H["MAUI handlers"] H --> WU["WinUI 3 - Windows App SDK"] B --> V["WebView2 in a MAUI, WPF or WinForms host"] U --> WR["Windows Runtime"] R --> N["Native Windows UI"] P --> E["Microsoft Edge engine"] WU --> W32["Win32, COM, DirectX"] V --> W32 WR --> W32 N --> W32 W --> W32 E --> W32

The same facts in table form, with the support status the official documentation gives:

Route What it is Language and UI Official status (October 2026)

.NET MAUI

One project targeting Android, iOS, macOS (Mac Catalyst) and Windows. On Windows the app is a WinUI 3 app.

C# and XAML, or C# only (MAUI has a code-only style, and the .NET MAUI Community Toolkit adds C# Markup).

Supported and actively developed; the cross-platform option in the Windows developer FAQ.

Blazor Hybrid

Razor components rendered in a WebView, hosted by a native app (MAUI, WPF or WinForms).

C#, Razor, HTML and CSS.

Supported. Not supported for WPF or WinForms apps on .NET Framework.

UWP

Sandboxed, always packaged apps on the Windows Runtime, device-family aware (Xbox, HoloLens, Surface Hub).

C#, C++, VB or JavaScript; UWP XAML.

Not deprecated, not under active development. Supported on modern .NET with Native AOT; the FAQ still names it for Xbox and standard Surface Hub apps.

Win32 and C++/WinRT

The native API layer and the C++17 projection of the Windows Runtime.

C++; XAML only through WinUI 3 with C++/WinRT.

Fully supported; the route for games, drivers, system tools and latency-critical code.

React Native for Windows

React Native with native Windows rendering, from a Microsoft open-source project.

JavaScript or TypeScript and React.

Documented by Microsoft as the route for teams with web skills (React Native for Desktop).

Progressive web app

A website installed as an app, optionally listed in the Microsoft Store.

HTML, CSS and JavaScript (or WebAssembly).

Documented by Microsoft Edge; no Windows-specific API surface beyond the browser’s.

Avalonia, Uno Platform

Third-party, open-source cross-platform XAML frameworks.

C# and XAML.

Not Microsoft products; see the third-party section.

.NET MAUI on Windows

What it is

NET Multi-platform App UI is the evolution of Xamarin.Forms: a cross-platform framework for native mobile and

desktop apps in C# and XAML, from a single shared code base. It targets Android, iOS, macOS and Windows, and the documentation also lists Tizen, which Samsung provides. The official description of its architecture is that .NET MAUI unifies the platform APIs into one API and still allows deep access to each native platform: your code mostly talks to the MAUI controls and API layer, which consumes the native platform APIs directly, and your code may also call platform APIs itself when it needs to.

For Windows, the platform framework underneath is WinUI 3. A Windows app built with .NET MAUI is a Windows App SDK app that uses the WinUI 3 library to create native apps for the Windows desktop, executing on the .NET runtime (the Mono-based runtime is used on Android, iOS and macOS only). The consequence that matters for choosing between the stacks of this section: a MAUI app on Windows looks like and integrates like a WinUI 3 app, but one translation layer sits between your code and the native controls.

Requirements and tooling

Item What the documentation says

Windows versions

Windows 11 and Windows 10 version 1809 or higher, using WinUI 3. The Android, iOS and macOS floors differ per .NET MAUI version.

Target framework moniker

A Windows TFM such as net10.0-windows10.0.19041.0. The windows10.0.19041.0 part is the Windows SDK version the project builds against.

Visual Studio

The ".NET Multi-platform App UI development" workload. Visual Studio Code with the .NET MAUI extension can also build Android, iOS and Windows apps on Windows.

Developer Mode

Needed on the machine to deploy a packaged MAUI Windows app. The default for a new project on .NET 9 and later is an unpackaged app, so Developer Mode is not required for the default launch profile.

iOS and Mac Catalyst

Need a networked Mac for the Apple builds. Not relevant to a Windows-only head.

Exact SDK and Windows App SDK pairing

The "Release versions" page on the dotnet/maui wiki lists which Windows App SDK each .NET MAUI release needs.

The archived Windows-developer page about MAUI mentions Visual Studio 2022 17.3 and the older workload name. It is kept as a historical page by Microsoft, so this page relies on the current dotnet/maui documentation instead.

The single project

A .NET MAUI app is a single SDK-style project that multi-targets the platforms. Per the documentation, the single project provides one shared project for all platforms, a simplified debug-target picker, shared resource files, one app manifest holding the title, ID and version, access to platform-specific APIs, and one cross-platform entry point. Platform folders under Platforms (Android, iOS, MacCatalyst, Windows, and so on) contain the code and resources that only compile for that platform. On Windows that folder contains the WinUI 3 entry point and the Package.appxmanifest MSIX manifest, which the deployment documentation names as Platforms\Windows\Package.appxmanifest.

A project file reduced to the Windows head looks like this. A real template lists all target platforms and adds the Windows moniker only when building on Windows. This abridged file is an illustration assembled from the documented properties, not a copy of a template.

<Project Sdk="Microsoft.NET.Sdk">

  <PropertyGroup>
    <TargetFrameworks>net10.0-windows10.0.19041.0</TargetFrameworks>
    <OutputType>Exe</OutputType>
    <RootNamespace>Bookshelf.Maui</RootNamespace>
    <UseMaui>true</UseMaui>
    <SingleProject>true</SingleProject>
    <ImplicitUsings>enable</ImplicitUsings>
    <Nullable>enable</Nullable>

    <!-- Shared app manifest data -->
    <ApplicationTitle>Bookshelf</ApplicationTitle>
    <ApplicationId>com.example.bookshelf</ApplicationId>
    <ApplicationDisplayVersion>1.0</ApplicationDisplayVersion>
    <ApplicationVersion>1</ApplicationVersion>

    <!-- Unpackaged is the default for new projects on .NET 9 and later -->
    <WindowsPackageType>None</WindowsPackageType>
  </PropertyGroup>

  <ItemGroup>
    <MauiIcon Include="Resources\AppIcon\appicon.svg" />
    <MauiFont Include="Resources\Fonts\*" />
    <MauiImage Include="Resources\Images\**\*" />
    <MauiAsset Include="Resources\Raw\**" />
  </ItemGroup>

  <ItemGroup>
    <PackageReference Include="CommunityToolkit.Mvvm" Version="8.4.2" />
    <ProjectReference Include="..\Bookshelf.Core\Bookshelf.Core.csproj" />
  </ItemGroup>

</Project>

The resource build actions are documented as follows. Images are source images from which the required resolutions are generated at build time.

Resource Build action Notes

App icon

MauiIcon

Resized to the sizes each platform needs; also used in the store listing.

Fonts

MauiFont

TTF or OTF, copied into the package.

Images

MauiImage

SVG or bitmap source images, resized per platform at build time.

Splash screen

MauiSplashScreen

Resized per platform.

Raw assets

MauiAsset

HTML, JSON, video; copied into the package.

CSS

MauiCss

Partial styling; loaded through a StyleSheet in a resource dictionary.

XAML

MauiXaml

Assigned automatically by the templates.

How a MAUI control becomes a WinUI control

MAUI controls are virtual views: they implement an interface such as IButton. A handler maps each virtual view to a native view. On Windows the native view is a WinUI control: the documentation names TextBox as the Windows native view of Entry. Two kinds of mapper connect them. The property mapper is a dictionary from the control’s properties to actions that update the native view when a property changes. The command mapper does the same for instructions the control sends to the native view, such as a ScrollView scrolling to a position (here "command" does not mean ICommand).

Every handler exposes the native view as PlatformView and the cross-platform control as VirtualView. Handlers have a lifecycle: HandlerChanging fires before a handler is removed or created and is the place to unsubscribe from native events, and HandlerChanged fires after the native view exists and all property values have been applied.

This is also why a MAUI page cannot simply contain a WinUI control. The Windows-developer page about MAUI states that .NET MAUI does not currently support using Windows App SDK controls, so existing WinUI 3 control libraries must be replaced with MAUI alternatives, or exposed through a custom handler.

Customising a handler for Windows

Handlers are customised by modifying the mapper with PrependToMapping, ModifyMapping or AppendToMapping. Each takes a string key and an action that receives the handler and the virtual view. A key that matches an interface property name, such as nameof(IEntry.IsPassword), runs whenever that property changes. Any other string is not tied to a property: the action runs only when the mapper is first applied to a handler, which happens once for each control instance as its handler is created, and never again on later property changes. Customisations are global: once a handler is changed, every control of that type in the app is affected. To change only some instances, subclass the control and test for the subclass inside the action.

The following selects all text in every Entry when it receives focus, on Windows only. PlatformView is a WinUI TextBox there.

using Microsoft.Maui.Handlers;

namespace Bookshelf.Maui;

public static class HandlerCustomizations
{
    public static void Apply()
    {
        EntryHandler.Mapper.AppendToMapping("SelectAllOnFocus", (handler, view) =>
        {
#if WINDOWS
            handler.PlatformView.GotFocus += (s, e) => handler.PlatformView.SelectAll();
#endif
        });
    }
}

The sample in the documentation attaches the equivalent code in a page constructor. Putting it in one static method that MauiProgram calls once is a common arrangement, with the caveat that the action still runs once per handler instance (the registration happens once, the mapping does not), so event subscriptions added this way are not removed; for long-lived pages, subscribe in HandlerChanged and unsubscribe in HandlerChanging as the documentation shows.

Platform-specific code can be separated in two ways, both documented: conditional compilation with #if WINDOWS (also ANDROID, IOS, MACCATALYST), or partial classes, where the cross-platform part declares partial methods and the implementation lives in the matching Platforms folder, so that platforms that do not implement it drop the call at compile time.

Bookshelf Desktop with a MAUI head

The shared pieces of Bookshelf Desktop do not depend on the UI framework. The Book record, IBookRepository and the view models live in libraries (Bookshelf.Core and the view-model assembly of the earlier MVVM pages), and only the views and the IDialogService implementation are UI-specific. A MAUI head therefore supplies a page, a dialog service, and the registration in MauiProgram. This is the same split used for WPF and WinUI 3 in the XAML Dialects page, and it is what makes MAUI a realistic add-on: the view-model code is reused as is.

The entry point builds a MauiApp and registers services with the same Microsoft.Extensions.DependencyInjection container used elsewhere in this section.

using Bookshelf.Core;
using Bookshelf.Desktop;
using Bookshelf.Desktop.ViewModels;

namespace Bookshelf.Maui;

public static class MauiProgram
{
    public static MauiApp CreateMauiApp()
    {
        var builder = MauiApp.CreateBuilder();
        builder.UseMauiApp<App>();

        // InMemoryBookRepository stands for any IBookRepository implementation.
        builder.Services.AddSingleton<IBookRepository, InMemoryBookRepository>();
        builder.Services.AddSingleton<IDialogService, MauiDialogService>();
        builder.Services.AddTransient<BooksViewModel>();
        builder.Services.AddTransient<BooksPage>();

        HandlerCustomizations.Apply();

        return builder.Build();
    }
}

App creates the window, as the single-project documentation shows for .NET 9 and later (MainPage assignment in the constructor is the older form):

namespace Bookshelf.Maui;

public partial class App : Application
{
    private readonly IServiceProvider _services;

    public App(IServiceProvider services)
    {
        InitializeComponent();
        _services = services;
    }

    protected override Window CreateWindow(IActivationState? activationState) =>
        new(_services.GetRequiredService<BooksPage>());
}

The page binds to the view model through compiled bindings. In MAUI the compile-time binding is turned on by declaring x:DataType, which must be a string literal or an x:Type extension. Inside a DataTemplate the data type has to be declared again, otherwise the compiler assumes the page’s type (warning XC0024).

<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             xmlns:vm="clr-namespace:Bookshelf.Desktop.ViewModels;assembly=Bookshelf.Desktop"
             x:Class="Bookshelf.Maui.BooksPage"
             x:DataType="vm:BooksViewModel"
             Title="Bookshelf">

    <Grid RowDefinitions="Auto,*,Auto" Padding="16" RowSpacing="12">

        <SearchBar Grid.Row="0"
                   Placeholder="Search by title or author"
                   Text="{Binding SearchText}" />

        <CollectionView Grid.Row="1"
                        ItemsSource="{Binding Books}"
                        SelectionMode="Single"
                        SelectedItem="{Binding SelectedBook}">
            <CollectionView.ItemTemplate>
                <DataTemplate x:DataType="vm:BookViewModel">
                    <VerticalStackLayout Padding="8">
                        <Label Text="{Binding Title}" FontAttributes="Bold" />
                        <Label Text="{Binding Author}" />
                    </VerticalStackLayout>
                </DataTemplate>
            </CollectionView.ItemTemplate>
        </CollectionView>

        <HorizontalStackLayout Grid.Row="2" Spacing="8">
            <Button Text="Load"   Command="{Binding LoadCommand}" />
            <Button Text="Add"    Command="{Binding AddBookCommand}" />
            <Button Text="Edit"   Command="{Binding EditSelectedCommand}" />
            <Button Text="Delete" Command="{Binding DeleteSelectedCommand}" />
            <Label Text="{Binding StatusMessage}" VerticalOptions="Center" />
        </HorizontalStackLayout>

    </Grid>
</ContentPage>
using Bookshelf.Desktop.ViewModels;

namespace Bookshelf.Maui;

public partial class BooksPage : ContentPage
{
    public BooksPage(BooksViewModel viewModel)
    {
        InitializeComponent();
        BindingContext = viewModel;
    }
}

The dialog service is the only UI-specific implementation. Alerts and prompts are methods on Page. In .NET 10 the documented names are DisplayAlertAsync, DisplayActionSheetAsync and DisplayPromptAsync; the .NET 8 and 9 documentation uses DisplayAlert and DisplayActionSheet. A two-button alert returns a bool, and a prompt returns null on cancel.

using Bookshelf.Core;

namespace Bookshelf.Desktop;

public sealed class MauiDialogService : IDialogService
{
    private static Page CurrentPage =>
        Application.Current?.Windows[0].Page
        ?? throw new InvalidOperationException("No window is open.");

    public Task<bool> ConfirmAsync(string title, string message) =>
        CurrentPage.DisplayAlertAsync(title, message, "Yes", "No");

    // A deliberately small editor: it only asks for a title. A full editor would be a
    // modal ContentPage bound to BookEditorViewModel, as in the WPF and WinUI 3 pages.
    public async Task<Book?> EditBookAsync(Book? existing)
    {
        string? title = await CurrentPage.DisplayPromptAsync(
            existing is null ? "New book" : "Edit book",
            "Title",
            initialValue: existing?.Title ?? string.Empty);

        if (string.IsNullOrWhiteSpace(title))
        {
            return null;
        }

        return existing is null
            ? new Book(0, title, "Unknown")
            : existing with { Title = title };
    }
}

Source: Display pop-ups

Packaged, unpackaged and publishing

Since .NET 9 a new MAUI project deploys unpackaged by default on Windows, which means launching from Visual Studio needs no Developer Mode. Converting between the two modes is a project property: Visual Studio’s "Create a Windows MSIX package" checkbox sets or removes WindowsPackageType=None in the project and flips the commandName of the Windows Machine profile in Properties/launchSettings.json between Project and MsixPackage. If the app has more than one launch profile, each one has to be edited by hand.

Aspect Packaged (MSIX) Unpackaged

Project property

No WindowsPackageType line (default is MSIX).

<WindowsPackageType>None</WindowsPackageType>

Launch profile

commandName: MsixPackage

commandName: Project

Developer Mode

Required to deploy from the IDE.

Not required.

Package identity

Yes; needed for APIs that require a packaged app and for Microsoft Store distribution.

No.

Manifest

Platforms\Windows\Package.appxmanifest, edited in the manifest designer (capabilities only in the XML editor).

Not used.

Output

An MSIX package.

An .exe and its folder.

Publishing is done with dotnet publish, scoped to the MAUI project. Publishing the whole solution makes dotnet publish attempt every project in it, which causes problems when other project types are present. For an unpackaged app on .NET 10:

dotnet publish -f net10.0-windows10.0.19041.0 -c Release `
  -p:RuntimeIdentifierOverride=win-x64 `
  -p:WindowsPackageType=None `
  -p:WindowsAppSDKSelfContained=true

The RuntimeIdentifierOverride parameter works around a Windows App SDK bug (issue 3337). Starting with .NET 10 the version-specific identifiers such as win10-x64 are no longer supported; use win-x64 or win-x86. The output is under bin\Release\net10.0-windows10.0.19041.0\win-x64\publish. Without WindowsAppSDKSelfContained=true the output does not include the runtime components, so the target machine needs them installed. The publish documentation also gives a property group for the project file that applies the same override. The packaged publish and the Visual Studio publish dialog have their own pages. Package signing, App Installer, ClickOnce (not applicable to MAUI) and Store submission are covered in the packaging pages of this section, and Blazor Hybrid apps additionally require a current WebView on the target machine.

MAUI compared with WPF, WinUI 3 and Windows Forms

Aspect .NET MAUI (Windows) WinUI 3 WPF Windows Forms

Platforms

Android, iOS, macOS, Windows

Windows only

Windows only

Windows only

XAML dialect

MAUI XAML (http://schemas.microsoft.com/dotnet/2021/maui)

WinUI XAML (Microsoft.UI.Xaml)

WPF XAML

None; designer-generated C#

Native controls

WinUI controls through handlers

WinUI controls directly

WPF-drawn controls

Wrappers over Win32 controls

Use WinUI 3 or Windows App SDK controls

Not currently; use a custom handler

Yes

No (XAML Islands, interop)

No

Binding

{Binding} plus compiled bindings via x:DataType

{Binding} and compiled {x:Bind}

{Binding}

Binding object in code

Triggers

Yes (Trigger, DataTrigger, behaviours, visual states)

Visual states only

Full trigger set

n/a

Window and desktop features

Cross-platform abstractions; Windows specifics through Platforms\Windows

Full Windows App SDK access

Win32 and .NET APIs; Windows App SDK partial

Win32 and .NET APIs

When to choose MAUI, and when not to

Choose MAUI when the same product must ship on at least one other platform (Android, iOS, macOS) and the team can accept a shared UI layer with a lowest-common-denominator control set. Choose it when the team already knows Xamarin.Forms and wants to keep XAML and C#. Choose it for desktop-only Windows apps only if there is a concrete reason to share code with a mobile app that will exist later. The Windows developer FAQ also says it is not currently possible to start with WinUI 3 and later add MAUI: teams expecting several platforms should begin with MAUI (or React Native for Desktop).

Do not choose it only to "use XAML on Windows". The Microsoft guidance for Windows-only apps names three reasons to stay with the Windows App SDK: familiarity (MAUI XAML has differences), native controls (existing WinUI 3 controls cannot be reused), and being closer to Windows (the MAUI translation step is a source of style, API and layout issues).

Blazor Hybrid

A Blazor Hybrid app puts Razor components in a native app instead of a web server. The .NET MAUI form uses a BlazorWebView control; the same components can also be hosted in WPF and Windows Forms apps on modern .NET (not on .NET Framework), which lets an existing desktop app add modern web UI. Native and hybrid parts can be mixed in the same app. Since .NET 9, MAUI additionally has a HybridWebView control for hosting non-Blazor JavaScript UIs such as Angular, React or Vue, with interop between C# and JavaScript.

On the platform side, two points matter. Blazor Hybrid needs a WebView on the host platform (WebView2 on Windows), and a .NET MAUI Blazor app has higher minimum versions on the mobile platforms than a plain MAUI app (the Windows floor is the same). The deployment documentation also warns that the WebView on the target machine must be kept current.

This section does not teach Razor. The component model, render modes, BlazorWebView registration and the MAUI, WPF and WinForms host setups are in Blazor WebAssembly, Hybrid, and Deployment, and the WebView2 side for WPF and WinForms is in Interop: Win32, WinForms & Web Content.

UWP

Status

UWP is "one of many ways to create client applications for Windows". The UWP guide itself says that developers who start now should consider the Windows App SDK and WinUI rather than UWP, and that UWP is still supported but not under active development. The FAQ adds the precise wording: UWP and WinUI 2 are not formally deprecated; WinUI 2.8 is the latest stable WinUI for UWP; and UWP developers should not feel pressured to migrate if they are satisfied with it.

The FAQ lists the cases where staying on UWP is the correct answer: Xbox apps, HoloLens 2D apps and apps for the standard Surface Hub environment. Windows IoT Enterprise supports desktop technologies, including the Windows App SDK, so an IoT target alone is not a reason for UWP. A Surface Hub 3 configured with Windows 11 Pro or Enterprise can run desktop app technologies as well.

UWP characteristic Detail

Application model

Built on the Windows Runtime through CoreApplication; one binary can reach many device families, depending on the API subset it calls.

Security

Sandboxed; capabilities declared in the manifest and authorised by the user.

Packaging

Always packaged, with MSIX; distributed through the Microsoft Store or other ways.

UI

UWP XAML (Windows.UI.Xaml) with WinUI 2 as the control library; also DirectX or HTML and JavaScript.

Languages

C#, Visual Basic, C++ and JavaScript.

UWP on modern .NET and Native AOT

The most significant recent change is not a feature of the UWP framework but of its runtime: UWP support for modern .NET is generally available and is the default project type for C# UWP apps in Visual Studio 2026. The old .NET Native toolchain is legacy and receives only security and reliability fixes. Visual Studio 2026 ships templates for a blank UWP app, a UWP CoreApplication app (no XAML), a Windows Runtime component and a UWP class library on the latest .NET. The prerequisites named in the documentation are Visual Studio 2026, the Universal Windows Platform tools component and the Windows 11 SDK 10.0.26100.0 or later.

A modern UWP project is SDK-style:

<Project Sdk="Microsoft.NET.Sdk">
  <PropertyGroup>
    <OutputType>WinExe</OutputType>
    <TargetFramework>net10.0-windows10.0.26100.0</TargetFramework>
    <TargetPlatformMinVersion>10.0.19041.0</TargetPlatformMinVersion>
    <UseUwp>true</UseUwp>
    <EnableMsixTooling>true</EnableMsixTooling>
    <PublishAot>true</PublishAot>
    <DisableRuntimeMarshalling>true</DisableRuntimeMarshalling>
  </PropertyGroup>
</Project>
Property Effect

UseUwp

References the WinRT projections for Windows.UI.Xaml types and configures C#/WinRT for UWP.

UseUwpTools

Enables the UWP XAML compiler, project capabilities and MSIX packaging; on by default when UseUwp is set.

EnableMsixTooling

Single-project MSIX; no separate packaging project.

PublishAot

Native AOT compilation. SelfContained is the alternative named for Store publishing.

DisableRuntimeMarshalling

Optimises marshalling for Native AOT.

IsAotCompatible

For library projects: marks the library as AOT compatible.

Migration from .NET Native has three steps in the documentation: convert the project to SDK style and add UseUwp, EnableMsixTooling and PublishAot or SelfContained; make the code AOT-compatible (reflection, dynamic code generation, third-party libraries; rd.xml files are replaced by attributes and analyzers, and classes that need {Binding} in XAML are marked partial and use [GeneratedBindableCustomProperty]); then build in Release with Native AOT and resolve all trim and AOT warnings. For Store publishing, build with PublishAot or SelfContained, create the MSIX as usual and upload it to Partner Center. Windows App Certification Kit failures about unsupported Win32 APIs can be ignored, as Partner Center no longer validates them for UWP apps.

This is also the first half of a two-step path to WinUI 3: move to modern .NET first, then migrate the UI framework and the app model separately. The FAQ is explicit that WinUI for UWP controls cannot be mixed with WinUI 3 controls and the Windows App SDK cannot be used inside a UWP app, so there is no control-by-control migration: the UI moves at once, and the decision guide for that is in the Windows App SDK migration documentation. UWP XAML controls can also be hosted the other way round, inside Win32 apps (WinForms, WPF, WinUI 3) with UWP XAML Islands on modern .NET.

The cost of moving to WinUI 3

Per the FAQ, the effort depends on five things: project file and MSBuild customisation, .NET API migration, availability of WinUI 3 versions of the UI component libraries, replacement of window and application-model APIs such as CoreWindow, ApplicationView and GetForCurrentView, and the C/CX projection (if used, it has to be ported to C/WinRT). Upgraded desktop apps can keep the application identity in the Store, so existing users are updated to the new version. Xbox, HoloLens and standard Surface Hub apps cannot migrate to WinUI 3.

Win32 and C++/WinRT

Win32 is the foundation under every other route in this page. WPF windows are HWNDs, WinUI 3 asks Win32 for a window handle, and WebView2 and DirectX are Win32 and COM components. Writing directly against Win32, COM and DirectX is the right choice for game engines, drivers, system utilities and latency-critical components; the FAQ’s own comparison puts C# as the default for business apps and C++ where direct hardware access, minimal runtime overhead or an existing C++ code base are decisive. The two are usually combined rather than chosen between.

Technology Role

Windows SDK

Headers, libraries, metadata and tools for operating-system APIs: Win32, WinRT, COM, DirectX, devices, shell. The Windows App SDK does not replace it.

C++/WinRT

A standard C17 language projection of the Windows Runtime. It replaces C/CX and WRL. Use it for a C WinUI 3 app, for authoring Windows Runtime components consumed by other languages, or when porting from C/CX.

C#/WinRT

The WinRT projection for C#. .NET apps targeting Windows get the WinRT APIs through the TFM; you need it explicitly to author Windows Runtime components in C# or to generate interop assemblies for third-party components.

CsWin32

A source generator for type-safe P/Invoke signatures; you list the APIs in NativeMethods.txt and call them through a generated PInvoke class. It replaces hand-written [DllImport] declarations.

P/Invoke and COM interop

Covered for C# in Native Interop.

The Windows App SDK can be used from an existing Win32, MFC, WPF or WinForms app for features that are independent of WinUI 3, such as app lifecycle, windowing and app notifications. The interop page of this section, Interop: Win32, WinForms & Web Content, shows the hosting direction (HwndHost, WindowsFormsHost) and the airspace issue.

React Native for Windows

React Native for Windows is a Microsoft open-source project that brings React Native to Windows. The FAQ presents it, together with React Native for macOS, as React Native for Desktop: a route for teams with strong JavaScript, TypeScript and React skills that renders UI to native primitives, with a "learn once, write anywhere" approach. It is a cross-platform route in the same sense as .NET MAUI, with a different language and ecosystem. The FAQ points out that React Native for Windows supports the Windows versions listed in its own compatibility documentation, and tells readers to verify device-family support for the version they target.

The project’s getting-started page, at the time of writing for React Native 0.85, creates a project and then adds the Windows platform:

npx --yes @react-native-community/cli@latest init Bookshelf --version 0.85.0
cd Bookshelf
npm install --save react-native-windows@^0.85.0
npx react-native init-windows --overwrite

Two statements from that page are worth recording. React Native for Windows runs exclusively on the New Architecture (Fabric): the legacy Paper architecture was removed in 0.82, so apps still on Paper must migrate before upgrading to 0.85. And the page does not state the supported Windows versions or describe the rendering pipeline; use its system requirements and compatibility pages for those. The generated Windows project is a Visual Studio solution that builds with the Debug configuration on x64 by default.

Progressive Web Apps

A PWA is a website built with HTML, CSS and JavaScript that can be installed and run on all devices from one code base, and that also runs in the browser. On Windows with Microsoft Edge, an installed PWA gets its own icon on the taskbar or Start menu, can be launched when an associated file type is opened or at sign-in, and can be submitted to the Microsoft Store. Documented capabilities include offline operation, push notifications, periodic background updates, file handling, sharing, clipboard access, Bluetooth and USB access, and WebAssembly.

The trade-off against native routes is the one that shapes the choice: a PWA reaches the Windows platform only through what the browser engine exposes. It cannot use the Windows App SDK, WinUI controls, or an MSIX package identity beyond what Store packaging provides. It is the best fit for an existing web product that needs an installed presence, and the cheapest route to every desktop operating system.

A minimal manifest (the file name and <link rel="manifest"> reference are conventional, and the fields are those documented by the web platform and the Edge PWA guidance):

{
  "name": "Bookshelf",
  "short_name": "Bookshelf",
  "start_url": "/",
  "display": "standalone",
  "background_color": "#ffffff",
  "theme_color": "#0f6cbd",
  "icons": [
    { "src": "/icons/icon-192.png", "sizes": "192x192", "type": "image/png" },
    { "src": "/icons/icon-512.png", "sizes": "512x512", "type": "image/png" }
  ]
}

Third-Party Options

The following frameworks are not Microsoft products and are not covered by the Microsoft documentation this section is built on. They are listed because a team evaluating cross-platform .NET UI will meet them. This page describes them in prose and gives no tutorials; read each project’s own documentation and licence before deciding, and verify their current version and Windows support there.

  • Avalonia (third-party; https://avaloniaui.net/) is an open-source, cross-platform UI framework for .NET under the MIT licence. It runs on Windows, macOS, Linux, iOS, Android and WebAssembly. Its distinguishing design is that it draws its own interface with the Skia rendering engine instead of wrapping native controls, so the UI looks the same on every target, in contrast to the MAUI handler model. Layouts are written in XAML (its own dialect, not WPF or WinUI XAML) and logic in C#, usually with MVVM. It is the choice that most often comes up when Linux desktop support is a requirement, which none of the Microsoft routes provide.

  • Uno Platform (third-party; https://platform.uno/) is an open-source (Apache 2.0) toolkit for building cross-platform .NET applications that runs on Windows, iOS, Android, WebAssembly, Linux and macOS. It is generally described as letting WinUI-style XAML and C# code run on those targets, which makes it a candidate for teams that already have UWP or WinUI code and want to reach other platforms. Check that relationship and its rendering model in the project’s own documentation before committing to it.

Both are alternatives to .NET MAUI, not to WinUI 3 on Windows: they matter when the requirement is a shared UI across operating systems, and the same questions apply as for MAUI (a shared control set versus direct platform access, the size of the dependency, the support model, and how the vendor handles new Windows App SDK features).

Choosing Among the Options

If the requirement is…​ Then consider

One C# and XAML code base for Windows, Android, iOS and macOS

.NET MAUI (or React Native for Desktop if the team is JavaScript-first)

A Windows-only app with the newest Windows features

WinUI 3 and the Windows App SDK (see the earlier pages of this section)

An existing web product that should feel installed

A PWA, or Blazor Hybrid if the front end is already Razor

An existing UWP app

Stay on UWP if it targets Xbox, HoloLens 2D or standard Surface Hub; move to modern .NET and Native AOT first; plan WinUI 3 separately

Games, drivers, system tools, existing C++ code

Win32 or C++/WinRT, with managed UI where it helps

Linux desktop in addition to Windows

A third-party framework such as Avalonia or Uno Platform, evaluated on its own terms

A WPF or WinForms app that needs a few new Windows features

Stay on the current stack and call the Windows App SDK APIs that do not need WinUI 3

Back to the broader comparison in Windows App Platforms: WPF, WinUI 3, WinForms, MAUI & More, and to the XAML differences in XAML Dialects: WPF, WinUI & MAUI.

Pitfalls

  • MAUI controls are not WinUI controls. A WinUI 3 control library does not drop into a MAUI page; it needs a custom handler or a replacement. Estimate that cost before choosing MAUI for an app that relies on a specific control suite.

  • Handler customisations are global. An AppendToMapping on EntryHandler changes every Entry in the app. Subclass the control and test view is MyEntry for instance-level changes, and unsubscribe native events in HandlerChanging.

  • x:DataType is required in DataTemplates. A missing declaration makes the compiler bind against the page’s type (XC0024), and x:DataType="x:Object" silently turns compiled bindings off for the subtree. Treat XC0022 and XC0025 as errors in CI, and note that MauiStrictXamlCompilation defaults to false unless the app is published with full trimming or Native AOT.

  • Packaged and unpackaged are different deployments. Converting changes the project property and every launch profile; the MAUI manifest designer cannot edit capabilities (use the XML editor); and APIs that need package identity, and Store distribution, need the packaged form.

  • Publish the project, not the solution. dotnet publish on a solution tries every project. On .NET 10, use win-x64 or win-x86 rather than win10-x64, and pass RuntimeIdentifierOverride.

  • Dialog method names changed. DisplayAlert is the .NET 8 and 9 name and DisplayAlertAsync the .NET 10 name; code shared across target frameworks needs a wrapper or conditional code.

  • A MAUI view-model assembly must not reference UI types. Keep Page, Application.Current and MainThread behind interfaces, as in IDialogService, or the view models cannot be shared with the WPF and WinUI 3 heads.

  • Native AOT for UWP needs AOT-compatible dependencies. Reflection-based serialisers and binding of untyped objects will fail at publish time or at run time; resolve trim and AOT warnings before you ship.

  • Blazor Hybrid depends on the installed WebView. Keep the WebView2 runtime current on the target machines.

  • Third-party frameworks follow their own release cycle. Check Windows App SDK and .NET version support in the project’s documentation before committing.

What the Official Documentation Does Not Provide

  • The Windows-developer page about MAUI is archived and still names Visual Studio 2022; the current .NET MAUI documentation holds the Windows setup, debugging and deployment pages used here.

  • There is no Microsoft Learn page that documents Native AOT for .NET MAUI on Windows, or a statement of which Windows App SDK version each .NET MAUI release uses (that lives in the dotnet/maui wiki "Release versions" page).

  • The React Native for Windows getting-started page does not state the supported Windows versions; they are in that project’s compatibility documentation.

  • Microsoft does not document Avalonia or Uno Platform; treat third-party claims as unverified until checked against the project.