Blazor Server单页多路由绑定不同ViewModel总选中第二个的问题
问题原因
Blazor 的
@inject指令属于编译期静态注入逻辑,不会受运行时@if判断块的控制。你写在两个判断块里的注入声明都会在页面编译阶段被处理,同名的viewmodel变量会被后声明的注入值覆盖,因此无论访问哪个路由,最终拿到的都是第二个ViewModel实例。
解决方案
推荐通过IServiceProvider在运行时动态获取对应ViewModel实例,操作步骤如下:
- 首先为两个ViewModel定义公共接口(可选但推荐,保证类型安全,避免后续绑定时的类型转换问题)
public interface ICanSimViewModel { // 把两个ViewModel共有的属性、方法声明在这里 } // 两个ViewModel分别实现该接口 public class CanSimStaicViewModell : ICanSimViewModel { // 原有逻辑 } public class CanSimDynamicViewModdels : ICanSimViewModel { // 原有逻辑 }
- 修改页面代码,移除判断块内的静态
@inject,改为运行时从DI容器获取实例:
@page "/canSimStatic" @page "/CanSimDynamic" @using System.Diagnostics; @using edge_cantraficSimulator.Data @using edge_cantraficSimulator.ViewModels @using System.Threading; @using System.IO; @using Microsoft.AspNetCore.Mvc.Rendering; @inject NavigationManager NavigationManager @inject IServiceProvider ServiceProvider @implements IAsyncDisposable @* 后续页面视图正常绑定viewmodel的属性即可 *@ <div>@viewmodel.SomeProperty</div> @code { private ICanSimViewModel viewmodel; protected override void OnInitialized() { if (NavigationManager.Uri.Contains("canSimStatic", StringComparison.OrdinalIgnoreCase)) { viewmodel = ServiceProvider.GetRequiredService<CanSimStaicViewModell>(); } else if (NavigationManager.Uri.Contains("CanSimDynamic", StringComparison.OrdinalIgnoreCase)) { viewmodel = ServiceProvider.GetRequiredService<CanSimDynamicViewModdels>(); } base.OnInitialized(); } // 如果你的ViewModel实现了IDisposable/IAsyncDisposable,需要手动释放 public async ValueTask DisposeAsync() { if (viewmodel is IAsyncDisposable asyncDisposable) { await asyncDisposable.DisposeAsync(); } else if (viewmodel is IDisposable disposable) { disposable.Dispose(); } } }
如果不想做接口抽象,也可以把viewmodel声明为dynamic类型,但会缺失编译期类型检查,不推荐。
可选替代方案
你也可以拆分两个独立页面分别对应两个路由,两个页面共用同一个布局组件做视图渲染,每个页面单独注入对应的ViewModel,逻辑更符合Blazor的常规设计,不需要额外处理动态注入的释放问题。
内容的提问来源于stack exchange,提问作者Timi21
相关产品推荐
相关产品推荐

