Shiny .NET v4 is here with BLE Windows Support, Improved GPS, & More! Check It Out
Shell Releases
v5.0 - April 21, 2026
Section titled “v5.0 - April 21, 2026” Feature
Tab badges —
INavigator now supports SetTabBadge(string route, int value), SetTabBadge<TViewModel>(int value), ClearTabBadge(string route), and ClearTabBadge<TViewModel>(), enabling numeric badges on Shell tabs by route or ViewModel mapping Feature
XAML navigation — new
Navigate attached properties enable route-based navigation directly from XAML on Button, MenuItem, and ToolbarItem, including support for a single parameter pair or a NavigationParameters collection Enhancement
Native badge support — tab badges are implemented natively for Android, iOS, Mac Catalyst, and Windows. Unsupported platforms such as Linux and macOS AppKit now throw
PlatformNotSupportedException instead of silently doing nothingv4.2 - April 15, 2026
Section titled “v4.2 - April 15, 2026” Feature
UxDivers Dialogs — new
Shiny.Maui.Shell.UxDiversDialogs package provides an alternative IDialogs implementation powered by UXDivers Popups. Drop-in replacement — no ViewModel changes needed, only the visual presentation changes Feature
UseUxDiversDialogs() extension methods — two extension methods for setup: MauiAppBuilder.UseUxDiversDialogs() initializes the UxDivers popup infrastructure, and ShinyAppBuilder.UseUxDiversDialogs() registers the IDialogs implementationUxDivers Dialogs Setup
Section titled “UxDivers Dialogs Setup”Install the package and the UxDivers dependency:
dotnet add package UXDivers.Popups.MauiAdd theme dictionaries to App.xaml:
<uxd:DarkTheme xmlns:uxd="clr-namespace:UXDivers.Popups.Maui.Controls;assembly=UXDivers.Popups.Maui" /><uxd:PopupStyles xmlns:uxd="clr-namespace:UXDivers.Popups.Maui.Controls;assembly=UXDivers.Popups.Maui" />Configure in MauiProgram.cs:
builder .UseMauiApp<App>() .UseUxDiversDialogs() // Initialize UxDivers popup infrastructure .UseShinyShell(x => x .UseUxDiversDialogs() // Register as IDialogs provider .AddGeneratedMaps() )| IDialogs Method | UxDivers Popup Used |
|---|---|
Alert | SimpleActionPopup (single button) |
Confirm | SimpleActionPopup (two buttons) |
Prompt | FormPopup with single FormField |
ActionSheet | OptionSheetPopup with OptionSheetItem per button |
v4.1 - April 13, 2026
Section titled “v4.1 - April 13, 2026” BREAKING Enhancement
AddGeneratedMaps() is no longer generated when nav extensions are disabled — setting ShinyMauiShell_GenerateNavExtensions to false now also prevents generation of NavigationBuilderExtensions.g.cs (AddGeneratedMaps). A SHINY002 warning is emitted when [ShellMap] attributes are detected but nav extensions are disabled Enhancement
AddGeneratedMaps() is no longer generated when no maps exist — NavigationBuilderExtensions.g.cs is now only produced when at least one [ShellMap] attribute is present, removing the empty stub that was previously always emittedMigration from v4.0
Section titled “Migration from v4.0”- If you relied on
AddGeneratedMaps()being available before adding any[ShellMap]attributes, add at least one[ShellMap]to generate the method - If you set
ShinyMauiShell_GenerateNavExtensionstofalsebut still usedAddGeneratedMaps(), either remove the property or replaceAddGeneratedMaps()with manual.Add<TPage, TViewModel>()calls
v4.0 - April 11, 2026
Section titled “v4.0 - April 11, 2026” Feature
INavigationBuilder — fluent builder for multi-segment Shell navigation URIs. Chain Add<TViewModel>(), Add(string), and PopBack() calls, then execute with a single Navigate(). Supports relative, root (fromRoot: true), and mixed pop/push patterns like ../../Page1/Page2 Feature
INavigator.CreateBuilder(bool fromRoot) — factory method to create an INavigationBuilder instance. Pass fromRoot: true to build absolute URIs prefixed with // Feature
Generated
INavigationBuilder extensions — source generator now produces NavigationBuilderNavExtensions.g.cs with typed Add{Name}() methods for each [ShellMap] ViewModel, enabling fluent chains like .AddDetail(id: 42).AddModal().Navigate() BREAKING Enhancement
relativeNavigation parameter — NavigateTo(string) and NavigateTo<TViewModel>() now accept bool relativeNavigation = true. When false, the URI is prefixed with // for root navigation. Replaces the previous SetRoot<TViewModel>() method Enhancement
Generated
NavigationExtensions — all generated NavigateTo{Name}() methods now include a bool relativeNavigation = true parameterMigration from v3.x
Section titled “Migration from v3.x”SetRoot<TViewModel>()has been removed — useNavigateTo<TViewModel>(relativeNavigation: false)instead- Calls to
NavigateTothat pass tuple args as positional parameters may need theargs:named parameter to disambiguate from the newbool relativeNavigationparameter
// Before (v3.x)await navigator.SetRoot<HomeViewModel>(vm => vm.Message = "Hello");await navigator.NavigateTo("details", ("Id", 42));
// After (v4.0)await navigator.NavigateTo<HomeViewModel>(vm => vm.Message = "Hello", relativeNavigation: false);await navigator.NavigateTo("details", args: [("Id", 42)]);
// New: Navigation Builderawait navigator .CreateBuilder() .AddDetail(id: 42) .AddModal() .Navigate();
// New: Pop back and pushawait navigator .CreateBuilder() .PopBack(2) .AddHome() .Navigate();v3.2.1 - April 8, 2026
Section titled “v3.2.1 - April 8, 2026” Fix
MainThread dispatch on macOS & Linux —
MauiMainThread now bypasses MainThread.InvokeOnMainThreadAsync on macOS and Linux, where MAUI’s implementation fails or deadlocks. INavigator and IDialogs dispatch calls now work reliably on both platforms Feature
IMainThread interface — thread-marshalling abstraction used internally by ShellNavigator and ShellDialogs, now registered as a singleton so you can inject it directly instead of using Microsoft.Maui.ApplicationModel.MainThread Feature
ShellServices record — convenience aggregate of INavigator, IDialogs, and IMainThread — inject a single parameter when a ViewModel needs most of them Feature
UseDialogs<TDialog>() — plug in a custom IDialogs implementation via UseShinyShell(x => x.UseDialogs<MyDialogs>()). The default ShellDialogs registration now uses TryAddSingleton so user overrides always winv3.2 - April 1, 2026
Section titled “v3.2 - April 1, 2026” Feature
ShinyShell base class — new
ShinyShell class that overrides OnNavigated to deterministically set the initial page’s BindingContext via Shell’s own lifecycle, eliminating a race condition where the Application.PageAppearing event could fire before the handler was registered Fix
BindingContext inheritance fix — BindingContext checks now correctly detect inherited values (e.g., the Shell instance propagated down the visual tree) instead of only checking for null, ensuring ViewModels are always assigned to their mapped pages
Migration from v3.1
Section titled “Migration from v3.1”Your AppShell (and any other Shell subclass) must now inherit from ShinyShell instead of Shell:
AppShell.xaml — change root element:
<shiny:ShinyShell x:Class="MyApp.AppShell" xmlns="http://schemas.microsoft.com/dotnet/2021/maui" xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml" xmlns:shiny="clr-namespace:Shiny;assembly=Shiny.Maui.Shell" xmlns:local="clr-namespace:MyApp" Title="MyApp"> <!-- ... --></shiny:ShinyShell>AppShell.xaml.cs — change base class:
using Shiny;
public partial class AppShell : ShinyShell{ public AppShell() { InitializeComponent(); }}v3.1.1 - March 17, 2026
Section titled “v3.1.1 - March 17, 2026” Fix
INavigationConfirmation no longer triggers during programmatic navigation — CanNavigate() is now only called for user-initiated navigation (back button, tab switches), not when navigating via INavigator methodsv3.1 - March 11, 2026
Section titled “v3.1 - March 11, 2026” Feature
SwitchShell — swap the entire active Shell at runtime via INavigator.SwitchShell(shell) or INavigator.SwitchShell<TShell>() (DI-resolved). Fires Navigating/Navigated events with NavigationType.SwitchShell and respects INavigationAware.OnNavigatingFrom Feature
SwitchShell<TShell>() — generic overload resolves the Shell from the DI container, enabling constructor-injected Shell instances Feature
NavigationType.SwitchShell — new enum value for tracking shell switches in navigation events and analyticsv3.0 - March 11, 2026
Section titled “v3.0 - March 11, 2026” Feature
IDialogs interface — new dedicated dialog service with
Alert, Confirm, Prompt, and ActionSheet methods, injected separately from INavigator for clean separation of concerns Feature
Prompt dialog — display a text input dialog with customizable keyboard type, placeholder, initial value, and max length Feature
[GitHub #1] by b4j4
ActionSheet dialog — display a multi-option action sheet with cancel and destructive action support BREAKING Enhancement
Alert and Confirm moved from INavigator to IDialogs — improves testability and follows interface segregationMigration from v2.x
Section titled “Migration from v2.x”INavigator.Alert()andINavigator.Confirm()have been removed — injectIDialogsinstead- Replace
navigator.Alert(...)withdialogs.Alert(...)andnavigator.Confirm(...)withdialogs.Confirm(...) - Add
IDialogsto your ViewModel constructor parameters where dialogs are used IDialogsis automatically registered byUseShinyShell()— no additional setup required
// Before (v2.x)public class MyViewModel(INavigator navigator){ await navigator.Alert("Error", "Something went wrong"); bool ok = await navigator.Confirm("Delete?", "Are you sure?");}
// After (v3.0)public class MyViewModel(INavigator navigator, IDialogs dialogs){ await dialogs.Alert("Error", "Something went wrong"); bool ok = await dialogs.Confirm("Delete?", "Are you sure?");
// New capabilities var name = await dialogs.Prompt("Name", "Enter your name"); var choice = await dialogs.ActionSheet("Options", "Cancel", null, "Edit", "Share");} Feature
Configurable source generation — disable route constants via
ShinyMauiShell_GenerateRouteConstants or navigation extensions via ShinyMauiShell_GenerateNavExtensions MSBuild properties (empty/missing = enabled, false = disabled) Feature
Route-based naming — the
route parameter in [ShellMap] now drives the generated constant name and navigation method name (e.g., [ShellMap<HomePage>("Dashboard")] → Routes.Dashboard, NavigateToDashboard) Feature
Invalid route diagnostic — SHINY001 compiler error when the route value is not a valid C# identifier (hyphens, spaces, leading digits)
Enhancement
AddGeneratedMaps() was always generated — even before any [ShellMap] attributes existed — so you could wire up MauiProgram.cs immediately (changed in v4.1: now requires at least one [ShellMap]) Enhancement
AddGeneratedMaps() now uses inline string literals instead of Routes.* constants, so it works correctly even when route constant generation is disabled Enhancement
When no route is specified, the generated name falls back to the page type name without the
Page suffix (e.g., [ShellMap<HomePage>] → Routes.Home)Migration from v2.1
Section titled “Migration from v2.1”- Route constant names may change if you specified explicit routes — e.g.,
Routes.Homefor[ShellMap<HomePage>("Dashboard")]is nowRoutes.Dashboard - Navigation extension method names change similarly —
NavigateToHomebecomesNavigateToDashboard - Routes with invalid C# identifiers (hyphens, spaces, leading digits) now produce compile errors — rename them to valid identifiers