Table of Contents

BLAZMVVM0005: Navigation Type Safety

Summary

Navigation calls must reference registered ViewModels with proper routes.

Description

This analyzer validates that NavigateTo calls reference ViewModels that are properly registered with [ViewModelDefinition] and have associated routable components. This prevents runtime navigation failures.

Severity

Error - Invalid navigation targets cause runtime errors.

Why This Rule Exists

  • Prevents runtime navigation failures
  • Ensures ViewModels are properly registered
  • Validates route existence at compile time
  • Improves type safety in navigation
  • Catches broken navigation links early

✅ DO: Correct Usage

// ViewModel with proper registration
[ViewModelDefinition(Lifetime = ServiceLifetime.Transient)]
public class ProductDetailsViewModel : ViewModelBase
{
    [ViewParameter]
    public int ProductId { get; set; }
}

// Component with route
@page "/products/{ProductId:int}"
@inherits MvvmComponentBase<ProductDetailsViewModel>

// Navigation - Type-safe
public class ProductListViewModel : ViewModelBase
{
    private readonly MvvmNavigationManager _navigation;

    public ProductListViewModel(MvvmNavigationManager navigation)
    {
        _navigation = navigation;
    }

    [RelayCommand]
    private void ViewProduct(int productId)
    {
        // ✅ Correct: Type-safe navigation to registered ViewModel
        _navigation.NavigateTo<ProductDetailsViewModel>(
            parameters: new { ProductId = productId });
    }
}

❌ DON'T: Incorrect Usage

// ❌ Wrong: Navigating to unregistered ViewModel
public class ProductListViewModel : ViewModelBase
{
    [RelayCommand]
    private void ViewProduct()
    {
        // Error: UnregisteredViewModel not decorated with [ViewModelDefinition]
        _navigation.NavigateTo<UnregisteredViewModel>();
    }
}

public class UnregisteredViewModel : ViewModelBase { }

// ❌ Wrong: ViewModel without associated route
[ViewModelDefinition]
public class NoRouteViewModel : ViewModelBase { }

// Missing: No component with @page directive for this ViewModel

// ❌ Wrong: Using string-based navigation (type-unsafe)
[RelayCommand]
private void Navigate()
{
    // Avoid: No compile-time validation
    _navigationManager.NavigateTo("/some/path");
}

How to Fix

Register the ViewModel

// Before
public class MyViewModel : ViewModelBase { }

_navigation.NavigateTo<MyViewModel>();  // Error

// After
[ViewModelDefinition(Lifetime = ServiceLifetime.Transient)]
public class MyViewModel : ViewModelBase { }

_navigation.NavigateTo<MyViewModel>();  // ✅ Valid

Create Associated Component

// ViewModel
[ViewModelDefinition]
public class MyViewModel : ViewModelBase { }

// Component with route
@page "/mypage"
@inherits MvvmComponentBase<MyViewModel>

<h3>My Page</h3>

Use Type-Safe Navigation

// Before
_navigationManager.NavigateTo("/products/123");

// After
_navigation.NavigateTo<ProductDetailsViewModel>(
    parameters: new { ProductId = 123 });

Benefits

Compile-Time Validation

// Catches errors at compile time
_navigation.NavigateTo<InvalidViewModel>();  // Won't compile if not registered

Refactoring Safety

// Renaming ViewModel updates all navigation calls
_navigation.NavigateTo<ProductDetailsViewModel>();  // IDE refactoring works

IntelliSense Support

// Auto-completion shows only valid ViewModels
_navigation.NavigateTo<|>  // Lists registered ViewModels

Simple Navigation

[RelayCommand]
private void GoToHome()
{
    _navigation.NavigateTo<HomeViewModel>();
}

With Parameters

[RelayCommand]
private void ViewProduct(int id)
{
    _navigation.NavigateTo<ProductDetailsViewModel>(
        parameters: new { ProductId = id });
}

With Query String

[RelayCommand]
private void Search(string query)
{
    _navigation.NavigateTo<SearchViewModel>(
        parameters: new { Query = query });
}

Code Fix

This analyzer provides an automatic code fix that adds the [ViewModelDefinition] attribute to the target ViewModel.

Additional Resources