我最终得到了一些改进的解决方案,它包装/封装了 NavigationManager,将所有内容保存在一个地方,并且不依赖于 Pages 或其他东西。它还将历史缓冲区大小保持在某个合理的范围内。
Navigation.cs
using System;
using System.Collections.Generic;
using Microsoft.AspNetCore.Components;
using Microsoft.AspNetCore.Components.Routing;
namespace MyApp
{
public class Navigation : IDisposable
{
private const int MinHistorySize = 256;
private const int AdditionalHistorySize = 64;
private readonly NavigationManager _navigationManager;
private readonly List<string> _history;
public Navigation(NavigationManager navigationManager)
{
_navigationManager = navigationManager;
_history = new List<string>(MinHistorySize + AdditionalHistorySize);
_history.Add(_navigationManager.Uri);
_navigationManager.LocationChanged += OnLocationChanged;
}
/// <summary>
/// Navigates to the specified url.
/// </summary>
/// <param name="url">The destination url (relative or absolute).</param>
public void NavigateTo(string url)
{
_navigationManager.NavigateTo(url);
}
/// <summary>
/// Returns true if it is possible to navigate to the previous url.
/// </summary>
public bool CanNavigateBack => _history.Count >= 2;
/// <summary>
/// Navigates to the previous url if possible or does nothing if it is not.
/// </summary>
public void NavigateBack()
{
if (!CanNavigateBack) return;
var backPageUrl = _history[^2];
_history.RemoveRange(_history.Count - 2, 2);
_navigationManager.NavigateTo(backPageUrl);
}
// .. All other navigation methods.
private void OnLocationChanged(object sender, LocationChangedEventArgs e)
{
EnsureSize();
_history.Add(e.Location);
}
private void EnsureSize()
{
if (_history.Count < MinHistorySize + AdditionalHistorySize) return;
_history.RemoveRange(0, _history.Count - MinHistorySize);
}
public void Dispose()
{
_navigationManager.LocationChanged -= OnLocationChanged;
}
}
}
然后你可以将这个类作为单例服务添加到依赖注入并初始化。
Program.cs
using System.Threading.Tasks;
using Microsoft.AspNetCore.Components.WebAssembly.Hosting;
using Microsoft.Extensions.DependencyInjection;
namespace MyApp
{
public class Program
{
public static async Task Main(string[] args)
{
var builder = WebAssemblyHostBuilder.CreateDefault(args);
builder.RootComponents.Add<App>("app");
builder.Services.AddSingleton<Navigation>();
// .. other services.
var host = builder.Build();
await Initialize(host);
await host.RunAsync();
}
private static async Task Initialize(WebAssemblyHost host)
{
host.Services.GetService<Navigation>();
// .. other initialization calls.
}
}
}
之后,您可以使用 Inject 指令/属性在任何您想要的地方使用它。
SomePage.cshtml
@page "/SomePage"
@inject Navigation Navigation
<h3>SomePage</h3>
<button @onclick="NavigateBackClick">Navigate Back</button>
@code {
private void NavigateBackClick()
{
Navigation.NavigateBack();
}
}
SomeService.cs
namespace MyApp
{
public class SomeService
{
private readonly Navigation _navigation;
public SomeService(Navigation navigation)
{
_navigation = navigation;
}
public void SomeMethod()
{
// ...
_navigation.NavigateBack();
}
}
}