You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.11 07:54:28