Install any skill in seconds. Free to start, no credit card required.
Get Started Free →Build, review, or migrate .NET MAUI applications across Android, iOS, macOS, and Windows with correct cross-platform UI, platform integration, and native packaging assumptions. USE FOR: working on cross-platform mobile or desktop UI in .NET MAUI; integrating device capabilities, navigation, or platform-specific code; migrating Xamarin.Forms or aligning. DO NOT USE FOR: unrelated stacks; generic tasks that do not need this specific guidance. INVOKES: inspect the repository context, edit targeted
.claude/skills/managedcode-maui/SKILL.md| Test case | Without → With | Effect | Δ tokens | Δ turns |
|---|---|---|---|---|
| case-13 | ✗→✓ | ▲ Improved | 59% | 0% |
| case-01 | ✓→✓ | = Same ✓ | 114% | 0% |
| case-02 | ✓→✓ | = Same ✓ | 141% | 0% |
| case-03 | ✓→✓ | = Same ✓ | 122% | 0% |
| case-04 | ✓→✓ | = Same ✓ | 91% | 0% |
| Platform | Build Host | Notes | |----------|------------|-------| | Android | Windows/Mac | Emulator or device | | iOS | Mac only | Requires Xcode | | macOS | Mac only | Catalyst | | Windows | Windows | WinUI 3 |
.NET MAUI 10.0.90 is a broad quality release for the 10.0 line. It fixes grouped CollectionView scrolling, layout, selection, and retention paths; Android BlazorWebView back handling; WebView rendering and lifecycle leaks; Shell/navigation regressions; and several shared-resource, handler, map, SafeArea, and accessibility issues.CollectionView flows, Shell/modal/back navigation, tabs, keyboard and SafeArea interactions, maps, WebView/HybridWebView lifecycle, memory retention, and accessibility narration on every shipped target..NET MAUI Learn overview for net-maui-10.0 still frames the platform around a shared single-project app, native API access, handlers, and optional Blazor Hybrid UI. Verify each target platform rather than treating shared code as identical runtime behavior.MyApp/
├── MyApp/ # Shared code
│ ├── App.xaml # Application entry
│ ├── MauiProgram.cs # DI and configuration
│ ├── Views/ # XAML pages
│ ├── ViewModels/ # MVVM ViewModels
│ ├── Models/ # Domain models
│ ├── Services/ # Business logic
│ └── Platforms/ # Platform-specific code
│ ├── Android/
│ ├── iOS/
│ ├── MacCatalyst/
│ └── Windows/
└── MyApp.Tests/csharppublic partial class ProductsViewModel(IProductService productService) : ObservableObject { [ObservableProperty] private ObservableCollection<Product> _products = []; [ObservableProperty] [NotifyCanExecuteChangedFor(nameof(LoadProductsCommand))] private bool _isLoading; [RelayCommand(CanExecute = nameof(CanLoadProducts))] private async Task LoadProductsAsync() { IsLoading = true; try { var items = await productService.GetAllAsync(); Products = new ObservableCollection<Product>(items); } finally { IsLoading = false; } } private bool CanLoadProducts() => !IsLoading; }
xml<ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui" xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml" xmlns:vm="clr-namespace:MyApp.ViewModels" x:Class="MyApp.Views.ProductsPage" x:DataType="vm:ProductsViewModel"> <RefreshView Command="{Binding LoadProductsCommand}" IsRefreshing="{Binding IsLoading}"> <CollectionView ItemsSource="{Binding Products}"> <CollectionView.ItemTemplate> <DataTemplate x:DataType="models:Product"> <VerticalStackLayout Padding="10"> <Label Text="{Binding Name}" FontSize="18" /> <Label Text="{Binding Price, StringFormat='{0:C}'}" /> </VerticalStackLayout> </DataTemplate> </CollectionView.ItemTemplate> </CollectionView> </RefreshView> </ContentPage>
csharppublic static class MauiProgram { public static MauiApp CreateMauiApp() { var builder = MauiApp.CreateBuilder(); builder .UseMauiApp<App>() .ConfigureFonts(fonts => { fonts.AddFont("OpenSans-Regular.ttf", "OpenSansRegular"); }); // Services builder.Services.AddSingleton<IProductService, ProductService>(); builder.Services.AddSingleton<INavigationService, NavigationService>(); // ViewModels builder.Services.AddTransient<ProductsViewModel>(); builder.Services.AddTransient<ProductDetailViewModel>(); // Pages builder.Services.AddTransient<ProductsPage>(); builder.Services.AddTransient<ProductDetailPage>(); return builder.Build(); } }
csharp// Register routes Routing.RegisterRoute(nameof(ProductDetailPage), typeof(ProductDetailPage)); // Navigate with parameters await Shell.Current.GoToAsync($"{nameof(ProductDetailPage)}?id={product.Id}"); // Receive parameters [QueryProperty(nameof(ProductId), "id")] public partial class ProductDetailViewModel : ObservableObject { [ObservableProperty] private string _productId; partial void OnProductIdChanged(string value) { LoadProduct(value); } }
csharppublic interface INavigationService { Task NavigateToAsync<TViewModel>(object? parameter = null); Task GoBackAsync(); } public class NavigationService : INavigationService { public async Task NavigateToAsync<TViewModel>(object? parameter = null) { var route = typeof(TViewModel).Name.Replace("ViewModel", "Page"); var query = parameter is null ? "" : $"?id={parameter}"; await Shell.Current.GoToAsync($"{route}{query}"); } public Task GoBackAsync() => Shell.Current.GoToAsync(".."); }
csharp// Services/DeviceService.cs (shared) public partial class DeviceService { public partial string GetDeviceId(); } // Platforms/Android/DeviceService.cs public partial class DeviceService { public partial string GetDeviceId() { return Android.Provider.Settings.Secure.GetString( Android.App.Application.Context.ContentResolver, Android.Provider.Settings.Secure.AndroidId); } } // Platforms/iOS/DeviceService.cs public partial class DeviceService { public partial string GetDeviceId() { return UIKit.UIDevice.CurrentDevice.IdentifierForVendor?.ToString() ?? ""; } }
csharppublic string GetPlatformInfo() { #if ANDROID return $"Android {Android.OS.Build.VERSION.Release}"; #elif IOS return $"iOS {UIKit.UIDevice.CurrentDevice.SystemVersion}"; #elif MACCATALYST return "macOS Catalyst"; #elif WINDOWS return "Windows"; #else return "Unknown"; #endif }
| Anti-Pattern | Why It's Bad | Better Approach | |--------------|--------------|-----------------| | God ViewModel | Unmaintainable | Split into focused ViewModels | | Logic in code-behind | Hard to test | Use MVVM and commands | | Platform code everywhere | Defeats cross-platform | Use handlers/DI | | Direct service calls in Views | Tight coupling | Use ViewModel | | Ignoring lifecycle | Crashes, leaks | Handle lifecycle events |
xml <ContentPage x:DataType="vm:ProductsViewModel">
xml <CollectionView ItemsSource="{Binding Items}" ItemSizingStrategy="MeasureFirstItem" />
csharp var image = ImageSource.FromFile("image.png"); // Use appropriate resolution for platform
csharp // Bad var data = service.GetData(); // Blocks UI
// Good var data = await service.GetDataAsync();
csharp[Fact] public async Task LoadProducts_UpdatesCollection() { var mockService = new Mock<IProductService>(); mockService.Setup(s => s.GetAllAsync()) .ReturnsAsync(new[] { new Product { Name = "Test" } }); var viewModel = new ProductsViewModel(mockService.Object); await viewModel.LoadProductsCommand.ExecuteAsync(null); Assert.Single(viewModel.Products); Assert.Equal("Test", viewModel.Products[0].Name); }
Other measured skills in the registry, with their headline benchmark lift.