.cursor/skills/dotnet-uno-platform/SKILL.md
Building Uno Platform apps. Extensions, MVUX reactive pattern, Toolkit controls, Hot Reload.
npx skillsauth add AGIBuild/Fulora dotnet-uno-platformInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
Uno Platform core development: Extensions ecosystem (Navigation, DI, Configuration, Serialization, Localization, Logging, HTTP, Authentication), MVUX reactive pattern, Toolkit controls, Theme resources (Material/Cupertino/Fluent), Hot Reload, and single-project structure. Covers Uno Platform 5.x+ on .NET 8.0+ baseline.
Scope boundary: This skill owns Uno Platform project structure, Extensions ecosystem configuration, MVUX patterns, Toolkit controls, theming, and Hot Reload. Per-target deployment (WASM, iOS, Android, Desktop, Embedded) is owned by [skill:dotnet-uno-targets]. MCP server integration for live documentation is owned by [skill:dotnet-uno-mcp].
Out of scope: Uno Platform testing (Playwright for WASM, platform-specific tests) -- see [skill:dotnet-uno-testing]. General serialization patterns -- see [skill:dotnet-serialization]. AOT/trimming for WASM -- see [skill:dotnet-aot-wasm]. UI framework selection decision tree -- see [skill:dotnet-ui-chooser].
Cross-references: [skill:dotnet-uno-targets] for per-target deployment, [skill:dotnet-uno-mcp] for MCP integration, [skill:dotnet-uno-testing] for testing patterns, [skill:dotnet-serialization] for serialization depth, [skill:dotnet-aot-wasm] for WASM AOT, [skill:dotnet-ui-chooser] for framework selection, [skill:dotnet-accessibility] for accessibility patterns (AutomationProperties, ARIA mapping on WASM).
Uno Platform 5.x uses a single-project structure with conditional TFMs for multi-targeting. One .csproj targets all platforms via multi-targeting.
<!-- MyApp.csproj -->
<Project Sdk="Uno.Sdk">
<PropertyGroup>
<TargetFrameworks>
net8.0-browserwasm;
net8.0-ios;
net8.0-android;
net8.0-maccatalyst;
net8.0-windows10.0.19041;
net8.0-desktop
</TargetFrameworks>
<OutputType>Exe</OutputType>
<UnoFeatures>
Extensions;
Toolkit;
Material;
MVUX;
Navigation;
Configuration;
Hosting;
Http;
Localization;
Logging;
LoggingSerilog;
Serialization;
Authentication;
AuthenticationOidc
</UnoFeatures>
</PropertyGroup>
</Project>
The UnoFeatures MSBuild property controls which Uno Extensions and theming packages are included. The Uno SDK resolves these features to the correct NuGet packages automatically.
MyApp/
MyApp/
App.xaml / App.xaml.cs # Application entry, resource dictionaries
MainPage.xaml / .xaml.cs # Initial page
Presentation/ # ViewModels or MVUX Models
Views/ # XAML pages
Services/ # Service interfaces and implementations
Strings/ # Localization resources (.resw)
en/Resources.resw
Assets/ # Images, fonts, icons
appsettings.json # Configuration (Extensions.Configuration)
Platforms/ # Platform-specific code (conditional compilation)
Android/
iOS/
Wasm/
Desktop/
MyApp.Tests/ # Unit tests (shared logic)
Uno Extensions provide opinionated infrastructure on top of the platform. All modules are registered through the host builder pattern.
// App.xaml.cs
public App()
{
this.InitializeComponent();
Host = UnoHost
.CreateDefaultBuilder()
.UseConfiguration(configure: configBuilder =>
configBuilder.EmbeddedSource<App>()
.Section<AppConfig>())
.UseLocalization()
.UseNavigation(RegisterRoutes)
.UseSerilog(loggerConfiguration: config =>
config.WriteTo.Debug())
.ConfigureServices((context, services) =>
{
services.AddSingleton<IProductService, ProductService>();
})
.Build();
}
Package: Uno.Extensions.Navigation
Region-based navigation with route maps, deep linking, and type-safe parameter passing. Navigation is driven declaratively from XAML or imperatively from code.
// Route registration
private static void RegisterRoutes(IViewRegistry views, IRouteRegistry routes)
{
views.Register(
new ViewMap(ViewModel: typeof(ShellModel)),
new ViewMap<MainPage, MainModel>(),
new ViewMap<ProductDetailPage, ProductDetailModel>(),
new DataViewMap<ProductDetailPage, ProductDetailModel, ProductEntity>()
);
routes.Register(
new RouteMap("", View: views.FindByViewModel<ShellModel>(),
Nested: new RouteMap[]
{
new("Main", View: views.FindByViewModel<MainModel>()),
new("ProductDetail", View: views.FindByViewModel<ProductDetailModel>())
})
);
}
<!-- XAML-based navigation using attached properties -->
<Button Content="View Product"
uen:Navigation.Request="ProductDetail"
uen:Navigation.Data="{Binding SelectedProduct}" />
Key concepts: Region-based navigation attaches navigation behavior to visual regions (Frame, NavigationView, TabBar). Route maps define the navigation graph. Deep linking maps URLs to routes for WASM.
Package: Uno.Extensions.Hosting
Uses Microsoft.Extensions.Hosting under the hood. Host builder pattern with service registration, keyed services, and scoped lifetimes.
.ConfigureServices((context, services) =>
{
// Standard DI registration
services.AddSingleton<IAuthService, AuthService>();
services.AddTransient<IOrderService, OrderService>();
// Keyed services (.NET 8+)
services.AddKeyedSingleton<ICache>("memory", new MemoryCache());
services.AddKeyedSingleton<ICache>("distributed", new RedisCache());
})
Package: Uno.Extensions.Configuration
Loads configuration from appsettings.json (embedded resource), environment-specific overrides, and runtime writeable options.
// appsettings.json
{
"AppConfig": {
"ApiBaseUrl": "https://api.example.com",
"MaxRetries": 3
}
}
// Binding to strongly-typed options
.UseConfiguration(configure: configBuilder =>
configBuilder
.EmbeddedSource<App>()
.Section<AppConfig>())
// AppConfig.cs
public record AppConfig
{
public string ApiBaseUrl { get; init; } = "";
public int MaxRetries { get; init; } = 3;
}
Package: Uno.Extensions.Serialization
Integrates System.Text.Json with source generators for AOT compatibility. Configures JSON serialization across the Extensions ecosystem.
.UseSerialization(configure: serializerBuilder =>
serializerBuilder
.AddJsonTypeInfo(AppJsonContext.Default.ProductDto)
.AddJsonTypeInfo(AppJsonContext.Default.OrderDto))
For general serialization patterns and AOT source-gen depth, see [skill:dotnet-serialization].
Package: Uno.Extensions.Localization
Resource-based localization using .resw files with runtime culture switching.
.UseLocalization()
<!-- Strings/en/Resources.resw -->
<!-- name: MainPage_Title.Text, value: Welcome -->
<!-- name: MainPage_LoginButton.Content, value: Log In -->
<!-- XAML: use x:Uid for automatic resource binding -->
<TextBlock x:Uid="MainPage_Title" />
<Button x:Uid="MainPage_LoginButton" />
Culture switching at runtime:
// Switch culture programmatically
var localizationService = serviceProvider.GetRequiredService<ILocalizationService>();
await localizationService.SetCurrentCultureAsync(new CultureInfo("fr-FR"));
Package: Uno.Extensions.Logging
Integrates with Microsoft.Extensions.Logging. Serilog integration for platform-specific sinks.
.UseSerilog(loggerConfiguration: config =>
config
.MinimumLevel.Information()
.WriteTo.Debug()
.WriteTo.Console())
Platform-specific sinks: Debug output for desktop, browser console for WASM, platform logcat for Android, NSLog for iOS.
Package: Uno.Extensions.Http
HTTP client integration with endpoint configuration. Supports Refit for typed API clients and Kiota for OpenAPI-generated clients.
.UseHttp(configure: (context, services) =>
services
.AddRefitClient<IProductApi>(context,
configure: builder => builder
.ConfigureHttpClient(client =>
client.BaseAddress = new Uri("https://api.example.com"))))
// Refit interface
public interface IProductApi
{
[Get("/products")]
Task<List<ProductDto>> GetProductsAsync(CancellationToken ct = default);
[Get("/products/{id}")]
Task<ProductDto> GetProductByIdAsync(int id, CancellationToken ct = default);
}
Package: Uno.Extensions.Authentication
OIDC, custom auth providers, and token management. Integrates with navigation for login/logout flows.
.UseAuthentication(auth =>
auth.AddOidc(oidc =>
{
oidc.Authority = "https://login.example.com";
oidc.ClientId = "my-app";
oidc.Scope = "openid profile email";
}))
Token management is automatic: tokens are stored securely per platform (Keychain on iOS/macOS, KeyStore on Android, Credential Manager on Windows, browser storage on WASM) and refreshed transparently.
MVUX is Uno's recommended reactive pattern, distinct from MVVM. It uses immutable records, Feeds, and States to model data flow declaratively. Source generators produce bindable proxies from plain model classes.
| Concept | Purpose | MVVM Equivalent | |---------|---------|-----------------| | Model | Immutable record defining UI state | ViewModel | | Feed | Async data source (loading/data/error states) | ObservableCollection + loading flag | | State | Mutable reactive state with change tracking | INotifyPropertyChanged property | | ListFeed | Feed specialized for collections | ObservableCollection | | Command | Auto-generated from public async methods | ICommand |
// ProductModel.cs -- MVUX model (source generators produce the bindable proxy)
public partial record ProductModel(IProductService ProductService)
{
// Feed: async data source with loading/error/data states
public IFeed<IImmutableList<ProductDto>> Products => Feed
.Async(async ct => await ProductService.GetProductsAsync(ct));
// State: mutable reactive value
public IState<string> SearchTerm => State<string>.Value(this, () => "");
// ListFeed with selection support
public IListFeed<ProductDto> FilteredProducts => SearchTerm
.SelectAsync(async (term, ct) =>
await ProductService.SearchProductsAsync(term, ct))
.AsListFeed();
// Command: auto-generated from async method signature
public async ValueTask AddProduct(CancellationToken ct)
{
var term = await SearchTerm;
await ProductService.AddProductAsync(term, ct);
}
}
<!-- ProductPage.xaml -- binds to generated proxy -->
<Page x:Class="MyApp.Views.ProductPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<StackPanel>
<TextBox Text="{Binding SearchTerm, Mode=TwoWay}" />
<FeedView Source="{Binding FilteredProducts}">
<FeedView.ValueTemplate>
<DataTemplate>
<ListView ItemsSource="{Binding Data}">
<ListView.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding Name}" />
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</DataTemplate>
</FeedView.ValueTemplate>
<FeedView.ProgressTemplate>
<DataTemplate>
<ProgressRing IsActive="True" />
</DataTemplate>
</FeedView.ProgressTemplate>
<FeedView.ErrorTemplate>
<DataTemplate>
<TextBlock Text="Error loading products" Foreground="Red" />
</DataTemplate>
</FeedView.ErrorTemplate>
</FeedView>
<Button Content="Add Product" Command="{Binding AddProduct}" />
</StackPanel>
</Page>
| Concern | MVUX | MVVM |
|---------|------|------|
| Model definition | Immutable record types | Mutable classes with INotifyPropertyChanged |
| Data loading | IFeed<T> with built-in loading/error states | Manual loading flags and try/catch |
| Collections | IListFeed<T> with immutable snapshots | ObservableCollection<T> with mutation |
| Commands | Auto-generated from async methods | ICommand implementations (RelayCommand) |
| State changes | IState<T> with explicit update semantics | Property setters firing PropertyChanged |
| Boilerplate | Minimal (source generators) | Significant (base classes, attributes) |
When to use MVUX: New Uno Platform projects, especially those with async data sources and complex loading states. MVUX eliminates most boilerplate and handles loading/error states declaratively.
When to use MVVM: Projects migrating from existing WPF/UWP/WinUI codebases, teams familiar with MVVM patterns, or projects using CommunityToolkit.Mvvm.
The Uno Toolkit provides cross-platform controls and helpers beyond stock WinUI controls. Enabled via UnoFeatures with Toolkit.
| Control | Purpose |
|---------|---------|
| AutoLayout | Flexbox-like layout with spacing, padding, and alignment |
| Card / CardContentControl | Material-style card surfaces with elevation |
| Chip / ChipGroup | Filter chips, action chips, selection chips |
| Divider | Horizontal/vertical separator lines |
| DrawerControl | Side drawer (hamburger menu) |
| LoadingView | Loading state wrapper with skeleton/shimmer |
| NavigationBar | Cross-platform navigation bar |
| ResponsiveView | Adaptive layout based on screen width breakpoints |
| SafeArea | Insets for notches, status bars, navigation bars |
| ShadowContainer | Cross-platform drop shadows via ThemeShadow |
| TabBar | Bottom or top tab navigation |
| ZoomContentControl | Pinch-to-zoom container |
| Helper | Purpose |
|--------|---------|
| CommandExtensions | Attach commands to any control (not just Button) |
| ItemsRepeaterExtensions | Selection and command support for ItemsRepeater |
| InputExtensions | Auto-focus, return key command, input scope |
| ResponsiveMarkupExtensions | Responsive values in XAML markup (e.g., Responsive.Narrow) |
| StatusBarExtensions | Control status bar appearance per-platform |
| AncestorBinding | Bind to ancestor DataContext in templates |
<!-- Vertical stack with spacing, padding, and alignment -->
<utu:AutoLayout Spacing="16" Padding="24"
PrimaryAxisAlignment="Start"
CounterAxisAlignment="Stretch">
<TextBlock Text="Product List"
Style="{StaticResource HeadlineMedium}" />
<utu:AutoLayout Spacing="8" Orientation="Horizontal">
<TextBox PlaceholderText="Search..."
utu:AutoLayout.PrimaryLength="*" />
<Button Content="Search"
utu:AutoLayout.CounterAlignment="Center" />
</utu:AutoLayout>
<ListView ItemsSource="{Binding Products}"
utu:AutoLayout.PrimaryLength="*" />
</utu:AutoLayout>
Uno supports Material, Cupertino, and Fluent design systems as theme packages. Themes provide consistent colors, typography, elevation, and control styles across all platforms.
<!-- UnoFeatures in .csproj -->
<UnoFeatures>Material</UnoFeatures> <!-- or Cupertino, or both -->
<!-- App.xaml -- theme resource dictionaries -->
<Application.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<!-- Material theme resources -->
<MaterialTheme />
<!-- Optional: color palette override -->
<ResourceDictionary Source="ms-appx:///Themes/ColorPaletteOverride.xaml" />
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</Application.Resources>
Override Material theme colors through ColorPaletteOverride.xaml:
<!-- Themes/ColorPaletteOverride.xaml -->
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<Color x:Key="PrimaryColor">#6750A4</Color>
<Color x:Key="SecondaryColor">#625B71</Color>
<Color x:Key="TertiaryColor">#7D5260</Color>
<Color x:Key="ErrorColor">#B3261E</Color>
</ResourceDictionary>
Use existing TextBlock styles from the theme system. Never set explicit font sizes -- use the Material type scale:
<TextBlock Text="Headline" Style="{StaticResource HeadlineMedium}" />
<TextBlock Text="Body text" Style="{StaticResource BodyLarge}" />
<TextBlock Text="Caption" Style="{StaticResource LabelSmall}" />
| Style | Typical Use |
|-------|------------|
| DisplayLarge/Medium/Small | Hero text, splash screens |
| HeadlineLarge/Medium/Small | Page titles, section headers |
| TitleLarge/Medium/Small | Card titles, dialog titles |
| BodyLarge/Medium/Small | Paragraph text, descriptions |
| LabelLarge/Medium/Small | Button labels, captions, metadata |
Switch between light and dark themes programmatically:
var themeService = serviceProvider.GetRequiredService<IThemeService>();
await themeService.SetThemeAsync(AppTheme.Dark);
var currentTheme = themeService.Theme;
Uno Platform provides Hot Reload across all targets via its custom implementation. Changes to XAML and C# code-behind are reflected without restarting the app.
| Change Type | Hot Reload Support | |-------------|-------------------| | XAML layout/styling | Full reload, instant | | C# code-behind (method bodies) | Supported via MetadataUpdateHandler | | New properties/methods | Requires rebuild | | Resource dictionary changes | Full reload | | Navigation route changes | Requires rebuild |
# Set environment variable before dotnet run
export DOTNET_MODIFIABLE_ASSEMBLIES=debug
# Run with Hot Reload
dotnet run -f net8.0-desktop --project MyApp/MyApp.csproj
Hot Reload is automatically configured by Visual Studio and VS Code (with Uno extension). For CLI usage, set DOTNET_MODIFIABLE_ASSEMBLIES=debug before running.
Gotcha: Hot Reload does not support adding new types, changing inheritance hierarchies, or modifying UnoFeatures. These require a full rebuild.
INotifyPropertyChanged. Do not add ObservableProperty attributes to MVUX models.UnoFeatures MSBuild property resolves packages automatically via the Uno SDK. Adding explicit PackageReference items for Extensions can cause version conflicts.{Binding StringFormat=...} in Uno XAML. It is a WPF-only feature. Use converters or multiple <Run> elements for formatted text.x:Static or {x:Reference} in bindings. These are WPF-only markup extensions not available in WinUI/Uno.HeadlineMedium, BodyLarge) to maintain design system consistency.PrimaryColor, SecondaryColor) or semantic brushes to maintain theme compatibility.AppBarButton outside a CommandBar. Use regular Button with icon content for standalone icon buttons.x:Uid for localization. Every user-visible string should use x:Uid referencing .resw resources, not hardcoded text.Uno.Sdk project SDK)dotnet workload install ios android maccatalyst wasm-toolstools
Captures learnings, errors, and corrections to enable continuous improvement. Use when: (1) A command or operation fails unexpectedly, (2) User corrects Claude ('No, that's wrong...', 'Actually...'), (3) User requests a capability that doesn't exist, (4) An external API or tool fails, (5) Claude realizes its knowledge is outdated or incorrect, (6) A better approach is discovered for a recurring task. Also review learnings before major tasks.
testing
Security headers configuration and best practices for ASP.NET Core Razor Pages applications. Covers CSP, HSTS, X-Frame-Options, and comprehensive security middleware setup. Use when configuring security headers in ASP.NET Core applications, implementing Content Security Policy (CSP), or setting up HSTS and other security-related HTTP headers.
development
Reviews designs and business goals for security vulnerabilities, data protection (in transit/at rest), authorization, and compliance alignment. Use when the user asks for a security review, threat modeling, attack surface analysis, data leakage prevention, or compliance/security assessment.
development
Best practices for building production-grade ASP.NET Core Razor Pages applications. Focuses on structure, lifecycle, binding, validation, security, and maintainability in web apps using Razor Pages as the primary UI framework. Use when building Razor Pages applications, designing PageModels and handlers, implementing model binding and validation, or securing Razor Pages with authentication and authorization.