Target frameworks
| Package | TFMs | MAUI? |
|---|---|---|
| Core, Validation, Pagination, Testing, Reactive, Compatibility | net10.0 | No |
| Host, Navigation, Dialogs | net10.0, net10.0-android (API 21+), net10.0-ios (iOS 15+), net10.0-maccatalyst (15+), net10.0-windows10.0.19041.0 (Windows 10 17763+; packed when MSBuild runs on Windows) | Yes |
| SourceGenerators | Roslyn analyzer / generator | — |
Host / Navigation / Dialogs are single-window hosts on Android, iOS, Mac Catalyst, and Windows (shared MAUI APIs). Defaults still use Windows[0] / Shell.Current. Multi-window desktop, Window.AddOverlay toast QA on desktop, and a Windows nupkg RID when packing on macOS are not a separate desktop product. Windows apps resolve net10.0 when the Windows TFM is not in the nupkg. Host APIs that need a window throw FeatureNotSupportedException on the net10.0 TFM. Sibling adapters (NetworkMonitor, SecureSession, DeepLinks, KeyboardManager, FormValidation) stay Android + iOS.
Threading, AOT, and security
- ObservableModel.SetProperty is not thread-safe. Property, command, and navigation notifications hop to IMainThread when MarshalNotifications is true (default).
- Do not ConfigureAwait(false) then new Page() or Shell.GoToAsync. Navigators hop first; NavigationThread.EnsurePageFactoryOnMainThread throws if they do not.
- Bind Button.Command to AsyncModelCommand only on 0.6.0-preview+. 0.5.0 raised CanExecuteChanged off the UI thread after ConfigureAwait(false).
- ICommand.Execute (async void) never throws. Failures go to IErrorSink / IDialogs. ExecuteAsync still rethrows.
- AsyncState updates are compare-exchange; PropertyChanged is marshalled when a dispatcher is present.
- INavigator is serialized per window. Concurrent navigations queue or fail as Outcome.
- Library pipeline code uses ConfigureAwait(false) except where the next step must run on the UI context.
- Typed NavigateToAsync<TViewModel>() is the AOT path. UseMvvmExpress applies generated [Route] / [RequiresAuth] via a ModuleInitializer. Convention scan of *Page / *ViewModel is opt-in and annotated.
- Call InitializeComponent() on App before resolving AppShell / pages (App(IServiceProvider) + CreateWindow).
- ViewModels do not store secrets. Tokens belong in Plugin.Maui.SecureSession / SecureStoragePlus.
- Authorization attributes only consult IAuthState supplied by the app.
Explicitly not public
- Prism INavigationService, IDialogService, INavigationParameters.
- CommunityToolkit ObservableObject, RelayCommand, [ObservableProperty], IMessenger (use Compatibility CommunityToolkitMessageHub to adapt).
- ReactiveUI ReactiveObject, ReactiveCommand, WhenAnyValue.
- A static MVVMExpress.Current in Core.
- Types that reference Page or Shell inside Core.