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:
Microsoft.UI.Xaml namespaces, so your code compiles without changes
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.
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
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:
#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
InitializeComponent() methods that construct the UI tree programmatically for each target platform.
Button and Grid that work identically across Windows, iOS, Android, WebAssembly, macOS, and Linux.
UIButton on iOS or Android Button views), while Skia draws all UI directly for pixel-perfect consistency across platforms.
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.
Subscribe to Our Blog
Subscribe via RSS
Back to Top