AgentStack
SKILL verified MIT Self-run

Maui

skill-managedcode-dotnet-skills-maui · by managedcode

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 t…

No reviews yet
0 installs
4 views
0.0% view→install

Install

$ agentstack add skill-managedcode-dotnet-skills-maui

✓ scanned · ✓ verified — works with Claude Code, Cursor, and more.

Security review

✓ Passed

No issues found. Passed automated security review. · v0.1.0 How review works →

  • Prompt-injection patterns
  • Secret / credential exfiltration
  • Dangerous shell & filesystem operations
  • Untrusted network calls
  • Known-malicious package signatures

What it can access

  • Network access No
  • Filesystem access No
  • Shell / process execution No
  • Environment & secrets No
  • Dynamic code execution No

From automated source analysis of v0.1.0. “Used” means the capability is present in the source — more access means more to trust, not that it’s unsafe.

Are you the author of Maui? Claim this listing to set pricing, connect Stripe payouts, and keep 70% of every sale.
Sign up to claim

About

.NET MAUI

Trigger On

  • working on cross-platform mobile or desktop UI in .NET MAUI
  • integrating device capabilities, navigation, or platform-specific code
  • migrating Xamarin.Forms or aligning a shared codebase across targets
  • implementing MVVM patterns in mobile apps

Documentation

References

  • [patterns.md](references/patterns.md) - Shell navigation, platform-specific code, messaging, lifecycle, data binding, and CollectionView patterns
  • [anti-patterns.md](references/anti-patterns.md) - Common MAUI mistakes and how to avoid them

Platform Targets

| Platform | Build Host | Notes | |----------|------------|-------| | Android | Windows/Mac | Emulator or device | | iOS | Mac only | Requires Xcode | | macOS | Mac only | Catalyst | | Windows | Windows | WinUI 3 |

Workflow

  1. Confirm target platforms — behavior differs across Android, iOS, Mac, Windows
  2. Separate shared UI and platform code — use handlers and DI
  3. Follow MVVM pattern — keep views dumb, logic in ViewModels
  4. Handle lifecycle and permissions — platform contracts need testing
  5. Test on real devices — emulators don't catch everything

Current Upstream Notes

  • .NET MAUI 10.0.71 is a servicing release for the 10.0 line. It includes fixes around HybridWebView/WebView rendering, modal navigation and tab behavior, SafeArea listeners in recycler items, MapPool retention, and platform-specific navigation regressions.
  • After upgrading MAUI packages, smoke-test Shell modal navigation, tabs, keyboard interactions, SafeArea layout, maps, WebView/HybridWebView, and accessibility narration on the target platforms.
  • The current .NET MAUI Learn overview for net-maui-10.0 remains the source for supported platforms, single-project structure, native API access, Blazor Hybrid, and migration positioning.

Project Structure

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/

MVVM Pattern

ViewModel with MVVM Toolkit

public partial class ProductsViewModel(IProductService productService) : ObservableObject
{
    [ObservableProperty]
    private ObservableCollection _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(items);
        }
        finally
        {
            IsLoading = false;
        }
    }

    private bool CanLoadProducts() => !IsLoading;
}

View Binding


    
        
            
                
                    
                        
                        
                    
                
            
        
    

Dependency Injection

public static class MauiProgram
{
    public static MauiApp CreateMauiApp()
    {
        var builder = MauiApp.CreateBuilder();
        builder
            .UseMauiApp()
            .ConfigureFonts(fonts =>
            {
                fonts.AddFont("OpenSans-Regular.ttf", "OpenSansRegular");
            });

        // Services
        builder.Services.AddSingleton();
        builder.Services.AddSingleton();

        // ViewModels
        builder.Services.AddTransient();
        builder.Services.AddTransient();

        // Pages
        builder.Services.AddTransient();
        builder.Services.AddTransient();

        return builder.Build();
    }
}

Navigation

Shell Navigation

// 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);
    }
}

Navigation Service

public interface INavigationService
{
    Task NavigateToAsync(object? parameter = null);
    Task GoBackAsync();
}

public class NavigationService : INavigationService
{
    public async Task NavigateToAsync(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("..");
}

Platform-Specific Code

Using Partial Classes

// 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() ?? "";
    }
}

Conditional Compilation

public 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-Patterns to Avoid

| 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 |

Performance Best Practices

  1. Use compiled bindings:

```xml

```

  1. Virtualize long lists:

```xml

```

  1. Optimize images:

``csharp var image = ImageSource.FromFile("image.png"); // Use appropriate resolution for platform ``

  1. Avoid synchronous work on UI thread:

```csharp // Bad var data = service.GetData(); // Blocks UI

// Good var data = await service.GetDataAsync(); ```

Testing

[Fact]
public async Task LoadProducts_UpdatesCollection()
{
    var mockService = new Mock();
    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);
}

Deliver

  • shared MAUI code with explicit platform seams
  • MVVM pattern with testable ViewModels
  • navigation and lifecycle behavior that fits each target
  • a realistic build and deployment path for the chosen platforms

Validate

  • cross-platform reuse is real, not superficial
  • platform-specific behavior is isolated and testable
  • MVVM pattern is followed consistently
  • build assumptions for Mac/iOS and Windows are explicit
  • performance is acceptable on target devices

Source & license

This open-source skill is cataloged on AgentStack and links to its original source — we do not rehost the code.

Install and usage instructions live in the source repository linked above.

Reviews

No reviews yet — be the first.

Versions

  • v0.1.0 Imported from the upstream source.