我最终得出了一个稍微改进的解决方案,它封装了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;
}
public void NavigateTo(string url)
{
_navigationManager.NavigateTo(url);
}
public bool CanNavigateBack => _history.Count >= 2;
public void NavigateBack()
{
if (!CanNavigateBack) return;
var backPageUrl = _history[^2];
_history.RemoveRange(_history.Count - 2, 2);
_navigationManager.NavigateTo(backPageUrl);
}
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>();
var host = builder.Build();
await Initialize(host);
await host.RunAsync();
}
private static async Task Initialize(WebAssemblyHost host)
{
host.Services.GetService<Navigation>();
}
}
}
在此之后,您可以使用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();
}
}
}