Blazor WebAssembly+ReactiveUI MVVM:如何在ViewModel中调用JS函数?
在Blazor WebAssembly的ReactiveUI ViewModel中调用JavaScript函数
你的问题核心在于ReactiveUI ViewModel默认没有被Blazor的依赖注入(DI)容器管理,导致IJSRuntime无论是属性注入还是构造注入都无法被正确填充,最终出现空引用异常。下面是完整的解决方案,一步步帮你解决问题:
1. 让ViewModel纳入Blazor的DI容器管理
首先,你需要把TestViewModel注册到Blazor的DI容器中,这样Blazor才能自动为它注入依赖。
在Program.cs中,在builder.Build()之前添加注册代码:
builder.Services.AddScoped<TestViewModel>();
2. 修改ViewModel,使用构造函数注入并处理异步操作
Blazor的DI对构造函数注入的支持更可靠,而且调用JavaScript的InvokeAsync是异步操作,需要配合ReactiveCommand的异步创建方法:
using ReactiveUI; using Microsoft.JSInterop; using System.Reactive.Tasks; public class TestViewModel : ReactiveObject { private readonly IJSRuntime _jsRuntime; // 通过构造函数注入IJSRuntime,添加空值检查避免后续异常 public TestViewModel(IJSRuntime jsRuntime) { _jsRuntime = jsRuntime ?? throw new ArgumentNullException(nameof(jsRuntime)); // 使用CreateFromTask创建异步命令,适配JS调用的异步特性 AlertCommand = ReactiveCommand.CreateFromTask(ShowAlertMessage); } public ReactiveCommand<Unit, Unit> AlertCommand { get; } // 改为异步方法,await JS调用 private async Task ShowAlertMessage() { await _jsRuntime.InvokeAsync<bool>("showAlert", "Hello World!"); } }
3. 在Blazor组件中注入ViewModel(而非手动new)
在你的Blazor页面/组件中,通过@inject指令获取ViewModel实例,不要手动new TestViewModel():
@inject TestViewModel ViewModel @implements IAsyncDisposable <button @onclick="TriggerAlert">Show Alert</button> @code { private void TriggerAlert() { // 执行ReactiveCommand,Subscribe处理后续逻辑(比如异常) _ = ViewModel.AlertCommand.Execute().Subscribe( _ => {}, ex => Console.WriteLine($"Command failed: {ex.Message}") ); } // 实现IAsyncDisposable清理命令资源(可选但推荐) public async ValueTask DisposeAsync() { ViewModel.AlertCommand.Dispose(); await Task.CompletedTask; } }
4. 确保JavaScript函数全局可用
最后,要确保showAlert函数在浏览器全局作用域中存在,比如在wwwroot/index.html的<body>末尾添加:
<script> function showAlert(message) { alert(message); return true; } </script>
为什么之前的方法失败?
- 属性注入
[Inject]:Blazor的[Inject]属性仅对继承ComponentBase的组件,或者由DI容器直接创建的类生效。如果你手动new TestViewModel(),DI不会自动填充这个属性。 - 构造函数注入:同理,如果ViewModel不是由DI容器创建的,构造函数的参数不会被自动注入,导致
IJSRuntime为null。 - 异步处理缺失:
InvokeAsync是异步方法,直接用ReactiveCommand.Create(同步版本)会导致异步操作被同步调用,可能引发意外问题。
内容的提问来源于stack exchange,提问作者Rahul
相关产品推荐
相关产品推荐

