Migration Prism & MVVM
Key Takeaways
  • DelegateCommand maps cleanly to RelayCommand from CommunityToolkit.Mvvm
  • IRegionManager maps to Uno.Extensions Navigation regions and route registration
  • EventAggregator maps to WeakReferenceMessenger with simpler subscriber lifetimes
  • Prism modules become feature-scoped IServiceCollection extension methods
  • Some patterns, such as the IConfirmNavigationRequest pipeline, do not have a 1:1 replacement

Who this is for: Prism WPF or former Silverlight developers planning to take an existing line-of-business application cross-platform with Uno Platform.

Why Move

Why Prism Teams Move to Uno Platform

Prism remains an active project, but the desktop and web targets it grew up with are aging. WPF is still supported on Windows. Silverlight is gone. Xamarin.Forms is end of life. Teams that built Composite Application style LOB apps on Prism now need a path that keeps the MVVM investment and reaches Windows, macOS, Linux, iOS, Android, and the browser from one C# and XAML codebase. Uno Platform is that path. The translation work is mostly mechanical because the patterns Prism made popular live on under different package names.

Mapping

Prism to Uno Platform Concept Mapping

Prism ConceptUno Platform ReplacementPackage
BindableBaseObservableObjectCommunityToolkit.Mvvm
DelegateCommandRelayCommandCommunityToolkit.Mvvm
DelegateCommand<T>RelayCommand<T>CommunityToolkit.Mvvm
EventAggregator / PubSubEventsWeakReferenceMessengerCommunityToolkit.Mvvm
IRegionManagerINavigator + Region.AttachedUno.Extensions.Navigation
INavigationAwareNavigation callbacks on VMUno.Extensions.Navigation
IDialogServiceINavigator dialog routesUno.Extensions.Navigation
Unity / DryIoc containerIServiceCollectionMicrosoft.Extensions.DI
IModule + ModuleCatalogFeature IServiceCollection extensionsMicrosoft.Extensions.DI
Bootstrapper / PrismApplicationIHostBuilder via HostingUno.Extensions.Hosting

The short version: CommunityToolkit.Mvvm replaces the Prism MVVM primitives, Uno.Extensions Navigation replaces region navigation, and Microsoft.Extensions.DependencyInjection replaces the IoC container.

Commands

From DelegateCommand to RelayCommand

Most Prism view models look like this:

Prism (Before)
public class CustomerViewModel : BindableBase
{
    private string _name;
    public string Name
    {
        get => _name;
        set => SetProperty(ref _name, value);
    }

    public DelegateCommand SaveCommand { get; }

    public CustomerViewModel()
    {
        SaveCommand = new DelegateCommand(Save, CanSave)
            .ObservesProperty(() => Name);
    }

    private void Save() { /* ... */ }
    private bool CanSave() => !string.IsNullOrWhiteSpace(Name);
}

In Uno Platform with CommunityToolkit.Mvvm, the same view model uses source generators:

Uno Platform (After)
public partial class CustomerViewModel : ObservableObject
{
    [ObservableProperty]
    [NotifyCanExecuteChangedFor(nameof(SaveCommand))]
    private string _name = string.Empty;

    [RelayCommand(CanExecute = nameof(CanSave))]
    private void Save() { /* ... */ }

    private bool CanSave() => !string.IsNullOrWhiteSpace(Name);
}

The mental model is identical: a property and a command bound from XAML. The Uno Platform version is shorter because the source generator emits the property change notifications, the command field, and the CanExecute wiring. The XAML binding stays the same.

Navigation

From IRegionManager to Uno.Extensions Navigation

Region navigation is the largest architectural pivot. Prism uses an IRegionManager and RegionManager.RegionName attached properties to associate a content host with a logical region, then calls RequestNavigate to swap views inside it. Uno.Extensions Navigation models the same idea with regions but expresses them as XAML attached properties and routes registered at startup.

A typical Prism shell has:

Prism (Before)
<!-- Prism -->
<ContentControl prism:RegionManager.RegionName="MainRegion" />

In Uno Platform you mark the host with Region.Attached and register routes:

Uno Platform (After)
<!-- Uno Platform -->
<Grid uen:Region.Attached="True">
  <Grid uen:Region.Attached="True"
        uen:Region.Name="ContentRegion" />
</Grid>
C#
// Route registration at startup
private static void RegisterRoutes(
    IViewRegistry views, IRouteRegistry routes)
{
    views.Register(
        new ViewMap(ViewModel: typeof(HomeViewModel)),
        new ViewMap<CustomerPage, CustomerViewModel>());

    routes.Register(
        new RouteMap("",
            View: views.FindByViewModel<ShellViewModel>(),
            Nested:
            [
                new RouteMap("Home",
                    View: views.FindByViewModel<HomeViewModel>(),
                    IsDefault: true),
                new RouteMap("Customer",
                    View: views.FindByViewModel<CustomerViewModel>())
            ]));
}

You navigate from a view model with INavigator.NavigateRouteAsync("Customer") instead of IRegionManager.RequestNavigate. The full registration pattern is documented in the Define Routes walkthrough, and the Define Regions walkthrough shows the matching XAML and view model code.

Messaging

From EventAggregator to WeakReferenceMessenger

Prism applications use IEventAggregator and PubSubEvents to broadcast loosely coupled messages between modules. CommunityToolkit.Mvvm ships WeakReferenceMessenger with the same publish-and-subscribe shape, plus automatic cleanup because subscribers are held weakly.

C#
// Define a message
public sealed record CustomerSavedMessage(int CustomerId);

// Publisher
WeakReferenceMessenger.Default
    .Send(new CustomerSavedMessage(customerId));

// Subscriber
WeakReferenceMessenger.Default
    .Register<CustomerSavedMessage>(this,
        (recipient, message) =>
        {
            // handle message
        });

Recipients registered with WeakReferenceMessenger do not require explicit unregistration, because they are collected when no other root keeps them alive. That removes a class of leaks that Prism teams worked around with SubscriptionToken bookkeeping.

For confirmation prompts and dialog flows that Prism handled through IDialogService, Uno.Extensions Navigation provides a Display Message Dialog pattern that uses the same INavigator surface as page navigation.

IoC & Modules

Modules, IoC, and the Bootstrapper

Prism's IModule, ModuleCatalog, and Bootstrapper map to a different shape in Uno Platform. Instead of a module loader, you organize feature registrations as IServiceCollection extension methods that the host calls during startup.

C#
// Feature registration (replaces an IModule)
public static class CustomersFeature
{
    public static IServiceCollection AddCustomers(
        this IServiceCollection services)
    {
        services.AddTransient<CustomerViewModel>();
        services.AddSingleton<ICustomerRepository,
            CustomerRepository>();
        return services;
    }
}

The host bootstrapper composes these feature methods. Constructor injection in your view models continues to work unchanged. The DI overview and DI setup guide document the registration helpers.

Tradeoffs

Tradeoffs and What Does Not Port Cleanly

Some Prism features do not survive the move with a 1:1 replacement. Plan for these explicitly:

  • IConfirmNavigationRequest pipeline. Prism's confirmation hook lets a view model veto navigation. Uno.Extensions Navigation does not expose the same pipeline; you implement equivalent gating in your own navigation interceptors or by guarding the command that triggers navigation.
  • Region-scoped containers. Prism's per-region scoped containers must be redesigned around scoped service providers from Microsoft.Extensions.DependencyInjection.
  • On-demand module loading. A ModuleCatalog with on-demand loading becomes explicit feature registration during host build. Lazy loading is possible but you design it yourself.
  • MVVM versus MVUX. CommunityToolkit.Mvvm is the closest mental model for a Prism team and the one this guide uses. MVUX is the reactive alternative built on feeds and states. The MVUX Commands walkthrough shows how commands work in that model. Adopt it only when the team is ready to rewrite view models around immutable state.

Scope before you commit. These are the items to plan for before you set a migration date. Everything else in the concept mapping table is a mechanical translation.

FAQ

FAQ

Is Prism compatible with Uno Platform?

Prism does not ship a Uno Platform target. The migration replaces Prism primitives with CommunityToolkit.Mvvm and Uno.Extensions Navigation equivalents. View models keep their MVVM structure; only the base classes, command type, and event aggregator references change.

What replaces DelegateCommand in Uno Platform?

Uno Platform projects use RelayCommand from CommunityToolkit.Mvvm, generated by the [RelayCommand] attribute on a method. The generator emits the command field, ICommand wiring, and CanExecute hooks, so each command is one annotated method in the view model.

Do I have to rewrite my view models?

Most Prism view models port with light edits. You change the base class from BindableBase to ObservableObject, replace DelegateCommand declarations with [RelayCommand] methods, and switch IEventAggregator calls to WeakReferenceMessenger. Property bindings and command bindings in XAML stay the same.

Should I move to MVVM or MVUX after migration?

CommunityToolkit.Mvvm is the closest mental model to Prism MVVM and is the recommended starting point. Adopt MVUX only when the team is ready to model state with immutable feeds and reactive operators, because it is a different architecture rather than a drop-in replacement.

Next Steps

Next Steps

You can land the migration in three passes: replace MVVM primitives with CommunityToolkit.Mvvm, replace region navigation with Uno.Extensions Navigation routes and regions, then replace the Prism bootstrapper with Uno.Extensions Hosting and Microsoft.Extensions.DependencyInjection.