NavigationFrame.Avalonia 2.0.9

The owner has unlisted this package. This could mean that the package is deprecated, has security vulnerabilities or shouldn't be used anymore.
dotnet add package NavigationFrame.Avalonia --version 2.0.9
                    
NuGet\Install-Package NavigationFrame.Avalonia -Version 2.0.9
                    
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="NavigationFrame.Avalonia" Version="2.0.9" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="NavigationFrame.Avalonia" Version="2.0.9" />
                    
Directory.Packages.props
<PackageReference Include="NavigationFrame.Avalonia" />
                    
Project file
For projects that support Central Package Management (CPM), copy this XML node into the solution Directory.Packages.props file to version the package.
paket add NavigationFrame.Avalonia --version 2.0.9
                    
#r "nuget: NavigationFrame.Avalonia, 2.0.9"
                    
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
#:package NavigationFrame.Avalonia@2.0.9
                    
#:package directive can be used in C# file-based apps starting in .NET 10 preview 4. Copy this into a .cs file before any lines of code to reference the package.
#addin nuget:?package=NavigationFrame.Avalonia&version=2.0.9
                    
Install as a Cake Addin
#tool nuget:?package=NavigationFrame.Avalonia&version=2.0.9
                    
Install as a Cake Tool

A modern, flexible, and Source Generator powered navigation framework for Avalonia applications. Inspired by Blazor and ASP.NET Core, it brings strongly-typed routing, powerful layout systems, automatic ViewModel wiring, and a robust authorization system to your desktop apps.

✨ Key Features

  • 🚀 Zero Runtime Reflection: Routes and View factories are generated at compile-time for maximum performance and type safety.
  • 🛡️ Strongly Typed Navigation: No more magic strings. Navigate using objects like new ProductRoute(123).
  • 🧩 Advanced Layout System: First-class support for nested layouts (e.g., Master -> Settings -> Profile).
  • 🧠 Smart ViewModel Inference: Automatically locates and wires up ViewModels based on naming conventions.
  • 🔐 Built-in Authorization: ASP.NET Core-style authorization with Policies, Roles, and UI helpers (AuthorizeView).
  • ⚡ Rich Lifecycle: Granular control over page events (IPreloadable, INavigatingFrom, INavigatedTo).
  • 🎨 Built-in Transitions: Slide, Fade, Zoom, and custom animations supported out of the box.
  • 🛠️ Roslyn Analyzers: Catch common errors (deadlocks, missing ViewModels) at compile time.

📑 Table of Contents


🚀 Getting Started

1. Setup Dependency Injection

Register the core services in your App.axaml.cs or DI configuration:

using NavigationFrame.Avalonia;
using Microsoft.Extensions.DependencyInjection;

public void ConfigureServices(IServiceCollection services)
{
    // 1. Register the ViewFactory (Generated)
    services.AddSingleton<IViewFactory, ViewFactory>();

    // 2. Register NavigationService
    // Standard service: Global navigation
    services.AddSingleton<INavigationService, NavigationService>();

    // OR Scoped service: Treats pages without layouts as scopes
    // services.AddSingleton<INavigationService, ScopedNavigationService>();

    // 3. Register your ViewModels
    services.AddTransient<HomeViewModel>();
    services.AddTransient<MainLayoutViewModel>();

    // 4. (Optional) Register Authorization
    // services.AddSingleton<IAuthenticationStateProvider, ...>();
}

2. Implement ViewFactory

Create a partial class marked with [ViewFactory]. The Source Generator will fill in the ResolveView logic automatically.

using NavigationFrame.Avalonia;

namespace MyApp.Services;

[ViewFactory]
public partial class ViewFactory : IViewFactory;

3. Initialize Navigation Host

In your main window, bind the NavigationService.Content to a content presenter.

MainWindow.axaml:

<Window ...>
    <Panel>
        
        <ContentControl Content="{Binding NavigationService.Content}" />

        
        <ProgressBar IsIndeterminate="True"
                     IsVisible="{Binding NavigationService.IsNavigating}"
                     VerticalAlignment="Top"/>
    </Panel>
</Window>

MainWindowViewModel.cs:

public class MainWindowViewModel : ViewModelBase
{
    public INavigationService NavigationService { get; }

    public MainWindowViewModel(INavigationService navService)
    {
        NavigationService = navService;

        // Setup default behaviors
        navService.HandleBackwardInput = true; // Alt+Left or MouseBack
        navService.HandleRefreshInput = true;  // F5

        // Navigate to start page
        _ = navService.NavigateAsync(new HomeRoute());
    }
}

🧭 Routing & Navigation

Defining Routes

Define a record for each page and mark it with [Route<TPage>].

// Simple Route
[Route<HomePage>]
public partial record HomeRoute;

// Route with Layout
[Route<SettingsPage, MainLayout>]
public partial record SettingsRoute;

Inject INavigationService into your ViewModels:

// Push a new page
await navigator.NavigateAsync(new SettingsRoute());

// Go back
await navigator.GoBackAsync();

// Go forward
await navigator.GoForwardAsync();

// Refresh (triggers IPreloadable again)
await navigator.RefreshAsync();

// Go to an existing page in the stack (or create if not found)
await navigator.GoToAsync(new HomeRoute());

Passing Parameters

Since routes are just objects, pass parameters via the constructor.

[Route<ProductPage>]
public partial record ProductRoute(int ProductId, string Category);

// Usage
await navigator.NavigateAsync(new ProductRoute(42, "Electronics"));

In your ProductViewModel:

public async Task PreloadAsync(IRoute route, NavigationMode mode, CancellationToken token)
{
    if (route is ProductRoute p)
    {
        await LoadProduct(p.ProductId);
    }
}

🧩 Layout System

Layouts are wrapper controls that provide a consistent UI structure (headers, sidebars, etc.).

Creating Layouts

  1. Create a UserControl.
  2. Implement IMountableControl.
  3. Mark with [Layout].
[Layout]
public partial class MainLayout : UserControl, IMountableControl
{
    // Return the container where the page content should be placed
    public Control GetMountPoint() => this.FindControl<ContentControl>("Body");
}

Nested Layouts

Layouts can be nested! Just specify the parent layout in the attribute.

// AuthLayout will be rendered INSIDE MainLayout
[Layout<MainLayout>]
public partial class AuthLayout : UserControl, IMountableControl
{
    public Control GetMountPoint() => this.FindControl<ContentControl>("InnerBody");
}

// Page uses AuthLayout (which uses MainLayout)
[Route<LoginPage, AuthLayout>]
public partial record LoginRoute;

🧠 ViewModel & Lifecycle

ViewModel Inference

The framework automatically finds ViewModels for your Views using these strategies (in order):

  1. Namespace.HomePageNamespace.HomeViewModel
  2. Namespace.Views.HomePageNamespace.ViewModels.HomeViewModel
  3. Namespace.HomePageNamespace.ViewModels.HomeViewModel
  4. Global Search: Any class named HomeViewModel in the assembly.

Manual Override:

[Route<MyPage>(DataContext = typeof(CustomViewModel))]
public partial record MyRoute;

Inherit Parent Context:

[Route<MyPage>(InheritContext = true)]
public partial record MyRoute;

Lifecycle Interfaces

Implement these interfaces in your ViewModel to hook into navigation events.

Interface Method Usage
IRequireNavigator SetNavigator Get the navigator instance.
INavigatingFrom OnNavigatingFromAsync Guard. Return false to cancel navigation (e.g., "Unsaved Changes").
IPreloadable PreloadAsync Background Thread. Load data before the page is shown.
INavigatedTo OnNavigatedToAsync Called when page becomes active.
INavigatedFrom OnNavigatedFromAsync Called when page is no longer active (paused).
IReleaseAware OnReleased Cleanup resources when page is removed from stack.

Data Loading Patterns

Use IPreloadable for heavy lifting to keep the UI responsive.

public class ProductViewModel : ViewModelBase, IPreloadable, INavigatedTo
{
    private ProductData? _data;

    // Runs in parallel with the exit animation of the previous page
    public async Task PreloadAsync(IRoute route, NavigationMode mode, CancellationToken token)
    {
        _data = await _service.FetchDataAsync(token);
    }

    public async Task OnNavigatedToAsync(IRoute route, Task preload, NavigationMode mode)
    {
        await preload; // Ensure loading finished (and propagate exceptions)
        Products = _data; // Update UI properties
    }
}

🔐 Authorization System

NavigationFrame includes a full-featured, policy-based authorization system inspired by ASP.NET Core.

Setup Authorization

// 1. Implement IAuthenticationStateProvider
services.AddSingleton<AppAuthenticationStateProvider>();
services.AddSingleton<IAuthenticationStateProvider>(sp => sp.GetRequiredService<AppAuthenticationStateProvider>());

// 2. Configure Options
var authOptions = new AuthorizationOptions();
authOptions.AddPolicy("CanEdit", policy => policy.RequireRole("Admin"));
services.AddSingleton(authOptions);

// 3. Register Service
services.AddSingleton<IAuthorizationService, AuthorizationService>();

Route Protection

Decorate your route records with [Authorize].

[Route<AdminPage>]
[Authorize(Roles = "Admin", Policy = "CanEdit")]
public partial record AdminRoute;

If a user tries to navigate here without permission, UnauthorizedNavigationException is thrown (catch this globally to redirect to Login).

UI Protection

Use AuthorizeView in your XAML to show/hide content based on permissions.

<nav:AuthorizeView Policy="CanEdit">
    <nav:AuthorizeView.Authorized>
        <Button Content="Edit Item" />
    </nav:AuthorizeView.Authorized>
    <nav:AuthorizeView.NotAuthorized>
        <TextBlock Text="Read Only Mode" />
    </nav:AuthorizeView.NotAuthorized>
</nav:AuthorizeView>

⚡ Advanced Features

Transitions

Control animations via NavOptions.

var options = new NavOptions
{
    Animation = PageAnimations.SlideLeft, // Built-in: Slide, Fade, Zoom, Dissolve
    // OR custom: new CompositeTransition(...)
};
await navigator.NavigateAsync(new DetailsRoute(), options);

Stack Manipulation

  • StackBehavior.Push: Standard history.
  • StackBehavior.Clear: Wipes history (e.g., after Login).
  • StackBehavior.Replace: Replaces current page.
  • IsEphemeral: Page won't be saved in history (skip over it when going back).

Smart Progress Indicator

The NavigationService.IsNavigating property is smart. It respects IndicatorShowDelay (default 500ms).

  • Fast navigation (<500ms): Indicator never shows (no flicker).
  • Slow navigation: Indicator shows and stays for at least IndicatorHideDelay to prevent jarring "flash".

🛠️ Diagnostics

We ship with Roslyn Analyzers to keep your code healthy:

  • NAV001: Ensure Layouts inherit from Control.
  • NAV002/003: ViewModel inference status (missing or inferred).
  • NAV005: Critical. Detects deadlocks if you await navigation inside lifecycle callbacks.
  • NAV008: Ensures Route classes are partial and not abstract.

💡 Best Practices

  1. Avoid Deadlocks: Never await navigation methods inside OnNavigatingFromAsync. If you need to redirect, use navigator.Post(NavigationMode.GoTo, ...) or return false and handle it separately.
  2. Use Records: Always use record for Routes. They provide value-based equality which is crucial for GoToAsync and stack matching.
  3. DI Lifecycle: The framework relies on your DI container. If you use AddTransient, a new ViewModel is created for each page visit. If AddSingleton, state persists.
Product Compatible and additional computed target framework versions.
.NET net8.0 is compatible.  net8.0-android was computed.  net8.0-browser was computed.  net8.0-ios was computed.  net8.0-maccatalyst was computed.  net8.0-macos was computed.  net8.0-tvos was computed.  net8.0-windows was computed.  net9.0 is compatible.  net9.0-android was computed.  net9.0-browser was computed.  net9.0-ios was computed.  net9.0-maccatalyst was computed.  net9.0-macos was computed.  net9.0-tvos was computed.  net9.0-windows was computed.  net10.0 is compatible.  net10.0-android was computed.  net10.0-browser was computed.  net10.0-ios was computed.  net10.0-maccatalyst was computed.  net10.0-macos was computed.  net10.0-tvos was computed.  net10.0-windows was computed. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.

NuGet packages

This package is not used by any NuGet packages.

GitHub repositories

This package is not used by any popular GitHub repositories.