A robust .NET library for implementing navigation stacks with undo/redo support, persistence capabilities, and event-driven architecture. Perfect for applications requiring navigation state management.
$ dotnet add package ktsu.NavigationA robust .NET library for implementing navigation stacks with undo/redo support and persistence capabilities.
ktsu.Navigation provides a complete navigation stack implementation that supports:
INavigationItemPerfect for applications that need robust navigation management, such as:
Add the NuGet package:
dotnet add package ktsu.Navigation
using ktsu.Navigation.Models;
using ktsu.Navigation.Services;
// Create navigation items
var page1 = new NavigationItem("page1", "Home Page");
var page2 = new NavigationItem("page2", "About Page");
var page3 = new NavigationItem("page3", "Contact Page");
// Create a navigation stack
var navigation = new Navigation<NavigationItem>();
// Navigate through items
navigation.NavigateTo(page1); // Current: Home Page
navigation.NavigateTo(page2); // Current: About Page
navigation.NavigateTo(page3); // Current: Contact Page
// Go back and forward
var previous = navigation.GoBack(); // Current: About Page
var next = navigation.GoForward(); // Current: Contact Page
// Check navigation state
Console.WriteLine($"Current: {navigation.Current?.DisplayName}");
Console.WriteLine($"Can go back: {navigation.CanGoBack}");
Console.WriteLine($"Can go forward: {navigation.CanGoForward}");
using ktsu.Navigation.Services;
// Create navigation with undo/redo support
var undoRedoProvider = new SimpleUndoRedoProvider(maxHistorySize: 50);
var navigation = new Navigation<NavigationItem>(undoRedoProvider);
navigation.NavigateTo(page1);
navigation.NavigateTo(page2);
// Undo the last navigation
undoRedoProvider.Undo(); // Back to page1
// Redo the navigation
undoRedoProvider.Redo(); // Forward to page2 again
using ktsu.Navigation.Services;
// Create navigation with JSON file persistence
var persistenceProvider = new JsonFilePersistenceProvider<NavigationItem>("navigation-state.json");
var navigation = new Navigation<NavigationItem>(undoRedoProvider: null, persistenceProvider: persistenceProvider);
navigation.NavigateTo(page1);
navigation.NavigateTo(page2);
// Save navigation state
await navigation.SaveStateAsync();
// Later... restore navigation state
await navigation.LoadStateAsync();
Console.WriteLine($"Restored to: {navigation.Current?.DisplayName}");
using ktsu.Navigation.Services;
// Create providers
var undoRedoProvider = new SimpleUndoRedoProvider();
var persistenceProvider = new JsonFilePersistenceProvider<NavigationItem>("app-navigation.json");
// Create navigation with all features
var navigation = new Navigation<NavigationItem>(undoRedoProvider, persistenceProvider);
// Subscribe to navigation events
navigation.NavigationChanged += (sender, e) =>
{
Console.WriteLine($"Navigation: {e.NavigationType}");
Console.WriteLine($"From: {e.PreviousItem?.DisplayName ?? "None"}");
Console.WriteLine($"To: {e.CurrentItem?.DisplayName ?? "None"}");
};
// Use factory for easier creation
var factory = new NavigationStackFactory(undoRedoProvider);
var anotherNavigation = factory.CreateNavigationStack<NavigationItem>(undoRedoProvider, persistenceProvider);
public class DocumentNavigationItem : INavigationItem
{
public string Id { get; }
public string DisplayName { get; set; }
public DateTime CreatedAt { get; }
public IReadOnlyDictionary<string, object> Metadata => _metadata.AsReadOnly();
private readonly Dictionary<string, object> _metadata = new();
public DocumentNavigationItem(string filePath, string displayName)
{
Id = filePath;
DisplayName = displayName;
CreatedAt = DateTime.UtcNow;
SetMetadata("FilePath", filePath);
SetMetadata("FileSize", new FileInfo(filePath).Length);
}
public void SetMetadata(string key, object value) => _metadata[key] = value;
public bool RemoveMetadata(string key) => _metadata.Remove(key);
}
// Use with navigation
var navigation = new Navigation<DocumentNavigationItem>();
var document = new DocumentNavigationItem("/path/to/file.txt", "My Document");
navigation.NavigateTo(document);
The library follows clean architecture principles with well-separated concerns:
NavigationItem, NavigationState - Core data structuresINavigation<T>: Main navigation operations interfaceINavigationItem: Contract for items that can be navigated toIPersistenceProvider<T>: Contract for persistence implementationsIUndoRedoProvider: Contract for undo/redo implementationsCreate custom persistence providers by implementing the IPersistenceProvider<T> interface:
public class DatabasePersistenceProvider<T> : IPersistenceProvider<T> where T : INavigationItem
{
public async Task SaveStateAsync(INavigationState<T> state, CancellationToken cancellationToken = default)
{
// Save to database
await Task.CompletedTask;
}
public async Task<INavigationState<T>?> LoadStateAsync(CancellationToken cancellationToken = default)
{
// Load from database
return await Task.FromResult<INavigationState<T>?>(null);
}
// Implement HasSavedState, ClearState, etc.
}
Contributions are welcome! Please feel free to submit a Pull Request.
MIT License. Copyright (c) ktsu.dev