Dotnet-skills dotnet-uno-platform
Build cross-platform .NET applications with Uno Platform targeting WebAssembly, iOS, Android, macOS, Linux, and Windows from a single XAML/C# codebase.
install
source · Clone the upstream repo
git clone https://github.com/managedcode/dotnet-skills
Claude Code · Install into ~/.claude/skills/
T=$(mktemp -d) && git clone --depth=1 https://github.com/managedcode/dotnet-skills "$T" && mkdir -p ~/.claude/skills && cp -r "$T/catalog/Frameworks/Uno-Platform/skills/dotnet-uno-platform" ~/.claude/skills/managedcode-dotnet-skills-dotnet-uno-platform && rm -rf "$T"
manifest:
catalog/Frameworks/Uno-Platform/skills/dotnet-uno-platform/SKILL.mdsource content
Uno Platform
Trigger On
- building cross-platform apps from a single C# and XAML codebase
- targeting WebAssembly, iOS, Android, macOS, Linux, and Windows simultaneously
- migrating WPF or UWP applications to cross-platform
- implementing pixel-perfect UI across all platforms
- using WinUI/UWP APIs on non-Windows platforms
Documentation
- Uno Platform Overview
- Getting Started
- Using Uno Platform with WinUI
- Platform-Specific Code
- MVUX Pattern
References
See detailed examples in the
references/ folder:
— MVUX, XAML, navigation, and performance patternspatterns.md
Platform Support
| Platform | Rendering | Notes |
|---|---|---|
| Windows | WinUI 3 | Native Windows App SDK |
| WebAssembly | Skia/Canvas | Runs in browser |
| iOS | Skia/Metal | Native iOS app |
| Android | Skia/OpenGL | Native Android app |
| macOS | Skia/Metal | Mac Catalyst or AppKit |
| Linux | Skia/X11 | GTK or Framebuffer |
Workflow
- Choose the right template — Uno Platform offers various templates for different scenarios
- Understand rendering modes — Skia vs native rendering affects performance and fidelity
- Apply MVVM or MVUX patterns — keep views dumb, logic in ViewModels
- Handle platform differences — use conditional XAML or partial classes
- Test on all target platforms — behavior varies across platforms
Project Structure
MyApp/ ├── MyApp/ # Shared code │ ├── App.xaml # Application entry │ ├── MainPage.xaml # Main page │ ├── Presentation/ # ViewModels (MVUX/MVVM) │ ├── Business/ # Business logic │ └── Services/ # Platform services ├── MyApp.Wasm/ # WebAssembly head ├── MyApp.Mobile/ # iOS and Android head ├── MyApp.Skia.Gtk/ # Linux head ├── MyApp.Skia.WPF/ # Windows Skia head └── MyApp.Windows/ # Native WinUI head
MVUX Pattern (Uno Extensions)
Model Definition
public partial record MainModel { public IListFeed<TodoItem> Items => ListFeed.Async(LoadItems); private async ValueTask<IImmutableList<TodoItem>> LoadItems(CancellationToken ct) { var items = await _todoService.GetAllAsync(ct); return items.ToImmutableList(); } }
View Binding with FeedView
<Page xmlns:uen="using:Uno.Extensions.Navigation.UI"> <utu:FeedView Source="{Binding Items}"> <utu:FeedView.ValueTemplate> <DataTemplate> <ListView ItemsSource="{Binding}"> <ListView.ItemTemplate> <DataTemplate x:DataType="local:TodoItem"> <TextBlock Text="{Binding Title}" /> </DataTemplate> </ListView.ItemTemplate> </ListView> </DataTemplate> </utu:FeedView.ValueTemplate> <utu:FeedView.ProgressTemplate> <DataTemplate> <ProgressRing IsActive="True" /> </DataTemplate> </utu:FeedView.ProgressTemplate> </utu:FeedView> </Page>
Classic MVVM with MVVM Toolkit
ViewModel
public partial class MainViewModel(ITodoService todoService) : ObservableObject { [ObservableProperty] private ObservableCollection<TodoItem> _items = []; [ObservableProperty] private bool _isLoading; [RelayCommand] private async Task LoadItemsAsync() { IsLoading = true; try { var items = await todoService.GetAllAsync(); Items = new ObservableCollection<TodoItem>(items); } finally { IsLoading = false; } } }
Platform-Specific Code
Conditional XAML
<TextBlock Text="Welcome" xmlns:win="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:android="http://uno.ui/android" xmlns:ios="http://uno.ui/ios" xmlns:wasm="http://uno.ui/wasm"> <win:TextBlock.Foreground> <SolidColorBrush Color="Blue" /> </win:TextBlock.Foreground> <android:TextBlock.Foreground> <SolidColorBrush Color="Green" /> </android:TextBlock.Foreground> </TextBlock>
Partial Classes
// Services/DeviceService.cs (shared) public partial class DeviceService { public partial string GetDeviceInfo(); } // Services/DeviceService.wasm.cs public partial class DeviceService { public partial string GetDeviceInfo() => "WebAssembly"; } // Services/DeviceService.Android.cs public partial class DeviceService { public partial string GetDeviceInfo() => $"Android {Android.OS.Build.VERSION.Release}"; }
Hot Reload and Development
// Enable Hot Reload in App.xaml.cs public App() { this.InitializeComponent(); #if DEBUG // Enable Hot Reload this.EnableHotReload(); #endif }
Anti-Patterns to Avoid
| Anti-Pattern | Why It's Bad | Better Approach |
|---|---|---|
| Platform code in shared | Breaks compilation | Use partial classes or #if |
| Ignoring Skia differences | Visual bugs | Test on all renderers |
| WPF assumptions | Not all APIs exist | Check Uno API coverage |
| Heavy XAML | Slow on WASM | Virtualize, simplify |
| Synchronous loading | UI freezes | Always use async |
Performance Best Practices
-
Use virtualized lists:
<ListView ItemsSource="{Binding Items}" VirtualizingPanel.VirtualizationMode="Recycling" /> -
Lazy load resources:
// Load images on demand var image = await ImageSource.LoadFromUriAsync(uri); -
Minimize XAML complexity:
- Avoid deep nesting
- Use compiled bindings (
where supported)x:Bind - Consider Skia-specific optimizations
-
WebAssembly specific:
- Minimize interop calls
- Use
for JS interopInvokeAsync - Consider AOT compilation for performance
Uno Extensions
// Use Uno.Extensions for enhanced patterns var builder = this.CreateBuilder(args) .Configure(host => host .UseConfiguration() .UseLocalization() .UseNavigation() .UseMvux() .ConfigureServices(services => { services.AddSingleton<ITodoService, TodoService>(); }));
Deliver
- single codebase running on web, mobile, and desktop
- consistent UI/UX across all platforms
- platform-specific optimizations where needed
- MVVM or MVUX patterns for testability
Validate
- app builds and runs on all target platforms
- platform-specific features work correctly
- performance is acceptable on WebAssembly
- Hot Reload works during development
- no WPF/UWP-only APIs are used without fallbacks