Uno Platform projects the WinUI API across every target, giving you a consistent XAML experience while handling the platform-specific rendering details. This article covers how WinUI and XAML work in Uno Platform, the difference between Skia and native rendering, and exactly what runs where when your app launches.

What is WinUI and why Uno Platform uses it

Uno Platform uses the WinUI API and XAML for a single codebase, which then runs on different platforms using one of two rendering modes: Native or Skia. WinUI is Microsoft’s modern native UI framework for Windows. It defines how you write XAML, how controls behave, and how the visual tree gets constructed.

Uno Platform chose WinUI as its API surface for a practical reason: it gives you a single, well-documented XAML dialect that works everywhere. When you write a Button or Grid in an Uno Platform app, you’re writing against WinUI types. The same code compiles for Windows, iOS, Android, WebAssembly, macOS, and Linux.

The evolution from UWP to WinUI 3

UWP tied XAML tightly to specific Windows SDK versions. If you wanted new controls or bug fixes, you had to wait for a Windows update. WinUI 3 changed that by decoupling the UI layer from the operating system entirely.

Now WinUI ships separately through the Windows App SDK. This separation made WinUI a practical foundation for cross-platform development because the API could evolve independently of any single platform.

WinUI as the foundation for cross-platform XAML

Uno Platform implements the WinUI API specification, not the older UWP APIs. Your XAML and C# code targets WinUI types regardless of where the app runs.

"

The TextBlock you use on Windows is the same TextBlock that compiles for Android. The Grid layout behaves identically on iOS.

What does that mean in practice? Your existing WinUI knowledge transfers directly to every platform Uno Platform supports.

How Uno Platform projects WinUI across platforms

The core technical concept here is “projection.” Uno Platform duplicates WinUI types so your code compiles against platform-specific implementations while maintaining source compatibility. You write code once, and Uno Platform provides the underlying implementation for each target.

Think of it like this: Microsoft defines what a Button is and how it behaves. Uno Platform then creates a Button implementation for iOS, another for Android, another for WebAssembly, and so on. Your code references the same Button class everywhere.

Type duplication and API mirroring

Uno Platform recreates WinUI types in each target platform’s runtime. Here’s how the mirroring works:

Type mirroring: Each WinUI class exists as a corresponding Uno Platform implementation for every supported platform
Namespace alignment: Types live in Microsoft.UI.Xaml namespaces, so your code compiles without changes
Behavioral parity: Implementations aim for identical behavior to native WinUI on Windows

This approach means a StackPanel on Android arranges its children the same way a StackPanel does on Windows. The API surface stays consistent.

The visual tree and layout system

When your app starts, Uno Platform builds a tree of UI elements. This visual tree mirrors what WinUI would create on Windows. Every Grid, Button, and TextBlock becomes a node in that tree.

The layout system follows WinUI specifications exactly. It uses the same two-pass approach: first a Measure pass to determine how much space each element wants, then an Arrange pass to position everything. A Grid with specific row and column definitions produces the same layout on every platform.

Compile-time XAML processing

XAML files are parsed at compile time, not runtime. The XAML compiler reads your .xaml files and generates C# code that constructs the UI tree programmatically.

Early Error Detection

Compile-time processing catches errors early. If you misspell a property name or reference a nonexistent resource, you'll see the error during build rather than when the app crashes at runtime.

The generated code creates InitializeComponent() methods that run when your page or control loads.

Rendering approaches in Uno Platform

Uno Platform offers two distinct rendering strategies. Understanding the difference helps you make informed architecture decisions for your app.

Skia-based rendering for pixel-perfect UI

Skia is Google’s open-source 2D graphics library. Chrome uses it. Android uses it. Flutter uses it. When Uno Platform uses Skia rendering, it draws every pixel directly onto a canvas, bypassing native controls entirely.

The result is identical appearance everywhere. A button looks exactly the same on iOS, Android, macOS, Linux, and WebAssembly. No platform-specific styling differences. This approach works well for apps where brand consistency matters more than matching the native platform look.

Native control rendering

The alternative approach maps XAML elements to native platform controls. On iOS, a Button becomes a UIButton. On Android, it becomes an Android Button view. The native platform handles the actual rendering.

Native rendering provides built-in accessibility support and platform-conventional appearance. Users get the look and feel they expect from their operating system. However, visual consistency across platforms becomes harder to achieve.

Choosing between Skia and native rendering

Consideration Skia Rendering Native Rendering
Visual consistency Pixel-identical across platforms Platform-native appearance
Platform integration Custom accessibility implementation Built-in accessibility support
Customization Full control over rendering Limited to native control capabilities
Typical use case Brand-consistent apps Platform-conventional apps

Skia is now the default in Uno Platform project templates. Most new projects use it for performance benefits and visual consistency. Native rendering remains available when platform integration is the priority.

XAML processing at compile time and runtime

XAML in Uno Platform apps goes through two phases. First, compilation turns your XAML into C# code. Then at runtime, that generated code constructs the actual UI.

XAML compilation and code generation

At build time, .xaml files become generated C# partial classes. The XAML compiler produces InitializeComponent() methods that construct the UI tree programmatically.

For example, if your XAML defines a Grid with two Button elements inside, the generated code creates a Grid object, creates two Button objects, and adds them as children. All of this happens in plain C# that you can inspect in your build output

Runtime visual tree construction

When the app runs, the generated code executes. It instantiates controls, sets properties, and assembles the visual tree. This happens once per page or control load.

After construction, the visual tree remains in memory until the page is navigated away from or explicitly unloaded. The layout system then measures and arranges everything to produce the final on-screen result.

Data binding and dependency properties

Data binding connects your UI to data. {Binding} expressions evaluate at runtime using reflection. {x:Bind} expressions compile to direct property access, offering better performance and compile-time error checking.

Dependency properties power the entire property system. They enable styling, animation, and data binding. When you set a property like Button.Background, you’re setting a dependency property that can participate in the broader WinUI property system.

For more details see documentation.

Where your UI code actually runs on each platform

This section answers the “what actually runs where” question directly. Each platform has specific runtime characteristics.

Windows with native WinUI

On Windows, Uno Platform can use actual WinUI 3. Your XAML runs through Microsoft’s native WinUI runtime, not Uno Platform’s implementation. This gives you full native performance and complete API compatibility.

Alternatively, you can use Skia rendering on Windows for consistency with other platforms. This is useful when you want identical appearance across all targets.

iOS and macOS

Skia backend: Uno Platform renders via SkiaSharp to a Metal or OpenGL surface. The entire UI is drawn by Skia.
Native backend: XAML elements map to UIKit views on iOS or AppKit/Catalyst views on macOS.

The Skia backend is recommended for most new projects. It provides visual consistency and avoids platform-specific rendering quirks.

Android

Android follows a similar pattern with both Skia backend (renders to an Android Canvas or OpenGL surface) and Native backend (XAML controls map to Android Views like TextView and Button).

With Skia, your app looks identical to the iOS version. With native rendering, it adopts Android’s Material Design appearance.

WebAssembly

The .NET runtime runs in the browser via WebAssembly. Your C# code executes directly in the browser without JavaScript interop for UI rendering.

Skia renders to an HTML Canvas element. The visual tree exists in .NET/WASM memory, not the DOM. This means you’re not manipulating HTML elements. You’re running a full .NET application that happens to draw to a canvas in the browser.

Linux and GTK

Skia renders to a GTK window surface. This enables desktop Linux support with the same codebase you use for other platforms. The GTK integration handles windowing and input while Skia handles all the drawing.

WinUI API compatibility and feature parity

A practical question: “Will my WinUI code work?” The answer depends on which APIs you’re using.

Supported controls and primitives

Uno Platform supports a comprehensive set of WinUI controls:

  • Layout containers: Grid, StackPanel, RelativePanel, Border, Canvas
  • Input controls: Button, TextBox, ComboBox, Slider, ToggleSwitch, CheckBox
  • Display controls: TextBlock, Image, MediaPlayerElement, ProgressRing
  • Collection controls: ListView, GridView, ItemsRepeater, FlipView

Handling platform-specific gaps

Some WinUI features have no equivalent on certain platforms. Uno Platform provides compile-time warnings when you use unsupported APIs. At runtime, unavailable features typically return safe defaults or no-op implementations.

You can use conditional compilation for platform-specific code paths:

C#
#if __IOS__
    // iOS-specific code
#elif __ANDROID__
    // Android-specific code
#endif

Extending with platform-specific code

Partial classes and platform-specific file naming conventions let you access native APIs when needed. Create a file named MyService.iOS.cs for iOS-specific implementation and MyService.Android.cs for Android.

This approach keeps your cross-platform code clean while allowing platform-specific customization where it matters. You can call native iOS or Android APIs directly when the cross-platform abstraction isn’t sufficient.

Start building cross-platform apps

Understanding how the UI layer works helps you make informed architecture decisions. Whether you choose Skia for pixel-perfect consistency or native rendering for platform integration, Uno Platform gives you the flexibility to build the right solution.

Frequently Asked Questions

XAML files compile to C# code at build time through the XAML compiler, which generates InitializeComponent() methods that construct the UI tree programmatically for each target platform.
Uno Platform implements the WinUI API specification, so you write against WinUI types like Button and Grid that work identically across Windows, iOS, Android, WebAssembly, macOS, and Linux.
Skia draws every pixel directly onto a canvas using Google's 2D graphics library, producing identical appearance across all platforms without using native controls.
The .NET runtime runs directly in the browser via WebAssembly, with your C# code executing without JavaScript interop and Skia rendering to an HTML Canvas element.
Native rendering maps XAML elements to platform controls (like UIButton on iOS or Android Button views), while Skia draws all UI directly for pixel-perfect consistency across platforms.
Platform-specific file naming conventions (like MyService.iOS.cs or MyService.Android.cs) and conditional compilation let you call native APIs directly when cross-platform abstractions aren't sufficient.
{Binding} expressions evaluate at runtime using reflection, while {x:Bind} expressions compile to direct property access for better performance and compile-time error checking.
The layout system follows WinUI specifications exactly, using a two-pass approach with Measure and Arrange phases that produce identical layouts across all platforms.