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

.NET MAUI(含BlazorWebView)与Vue3项目双向通信方案咨询

问题描述

现有一个集成BlazorWebView的.NET MAUI项目,XAML结构如下:

<?xml version="1.0" encoding="utf-8"?>

<ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             xmlns:local="clr-namespace:MauiApp1"
             x:Class="MauiApp1.MainPage">

    <VerticalStackLayout Spacing="20" Padding="20" Background="#25a6fb">
        <Label Text="Communicate between MAUI (C#) and BlazorWebView (JS)" TextColor="White" FontSize="20"
               FontAttributes="Bold" HorizontalTextAlignment="Center" HorizontalOptions="Center" />
        <VerticalStackLayout BackgroundColor="#25a6fb" Padding="10" Spacing="10">
            <Frame Padding="10, 5">
                <Entry x:Name="MauiEntry" Placeholder="Entry from MAUI" PlaceholderColor="Gray" TextColor="Gray" />
            </Frame>
            <HorizontalStackLayout HorizontalOptions="Center" Spacing="20">
                <Button Text="MAUI to WebView" Clicked="MauiToWebView" />
            </HorizontalStackLayout>
        </VerticalStackLayout>
        <BlazorWebView x:Name="BlazorWebView" HostPage="wwwroot/dist/index.html" WidthRequest="375" HeightRequest="400">
            <BlazorWebView.RootComponents>
                <RootComponent Selector="app" ComponentType="{x:Type local:Main}" />
            </BlazorWebView.RootComponents>
        </BlazorWebView>
        <VerticalStackLayout>
        </VerticalStackLayout>
    </VerticalStackLayout>

</ContentPage>

同时搭配一个基础Vue3项目,构建后通过符号链接将dist文件夹引入MAUI项目,BlazorWebView加载其index.html。尝试通过Blazor的JSInterop实现双向调用,但点击XAML中的按钮触发PrintDotNetObject方法时,出现IJSRuntime空引用异常。

Blazor组件Main.razor代码:

@inject IJSRuntime Js

<Router AppAssembly="@typeof(Main).Assembly">
    <Found Context="routeData">
        <RouteView RouteData="@routeData"/>
        <FocusOnNavigate RouteData="@routeData" Selector="h1"/>
    </Found>
    <NotFound>
        <LayoutView>
            <p role="alert">Sorry, there's nothing at this address.</p>
        </LayoutView>
    </NotFound>
</Router>

<br><br>
<code @ref="_codeBlock"></code>
@code
{
    private ElementReference _codeBlock;

    public async Task PrintDotNetObject()
    {
        var obj = new {
            FistName = "Jon",
            LastName = "Doe",
            Age = 27,
            BirthDate = DateTime.Now.AddYears(-27),
            LikesDotNet = true
        };
        await Js.InvokeVoidAsync("dotNetMauiApp.getMessage", _codeBlock, obj);
    }
}

Vue3对应代码:

<script>
export default {
  name: "MauiCommunication",
  mounted() {
    window.dotNetMauiApp = {
      getMessage: function(node, objectFromDotNet)
      {
        node.textContent = JSON.stringify(objectFromDotNet);
        return window.alert("Called From MAUI " + node.textContent)
      }
    };
  }
}
</script>
修复IJSRuntime空引用问题

空引用的核心原因是:直接从XAML的按钮点击事件调用Blazor组件的方法时,Blazor组件可能尚未完成初始化,或者IJSRuntime注入上下文未绑定到当前组件实例。

方案1:通过BlazorWebView的JsRuntime直接调用

跳过Blazor组件,直接使用MAUI中BlazorWebView自带的JsRuntime属性执行JS调用,无需依赖Blazor组件的注入:

  1. 修改XAML的按钮点击事件代码(MainPage.xaml.cs):
private async void MauiToWebView(object sender, EventArgs e)
{
    var obj = new
    {
        FistName = "Jon",
        LastName = "Doe",
        Age = 27,
        BirthDate = DateTime.Now.AddYears(-27),
        LikesDotNet = true
    };
    // 直接使用BlazorWebView的JsRuntime
    await BlazorWebView.JsRuntime.InvokeVoidAsync("dotNetMauiApp.getMessage", "", obj);
}
  1. 调整Vue的getMessage方法,适配参数变化:
getMessage: function(objectFromDotNet)
{
    const jsonStr = JSON.stringify(objectFromDotNet);
    // 假设Vue页面有一个id为message的元素用于展示内容
    document.getElementById('message').textContent = jsonStr;
    alert("Called From MAUI " + jsonStr);
}

方案2:确保Blazor组件已初始化并获取实例

如果必须通过Blazor组件调用,需要先获取Blazor组件的实例,确保其IJSRuntime已注入完成:

  1. 在MainPage.xaml.cs中,监听根组件初始化事件获取实例:
private Main _blazorMainComponent;

protected override void OnInitialized()
{
    base.OnInitialized();
    BlazorWebView.RootComponents.Added += RootComponents_Added;
}

private void RootComponents_Added(object sender, RootComponentEventArgs e)
{
    if (e.Component is Main mainComponent)
    {
        _blazorMainComponent = mainComponent;
    }
}

private async void MauiToWebView(object sender, EventArgs e)
{
    if (_blazorMainComponent != null)
    {
        await _blazorMainComponent.PrintDotNetObject();
    }
}
  1. 优化Blazor组件的注入验证:
@code
{
    [Inject]
    public IJSRuntime Js { get; set; }

    private ElementReference _codeBlock;

    protected override async Task OnInitializedAsync()
    {
        if (Js == null)
        {
            throw new InvalidOperationException("IJSRuntime未成功注入");
        }
        await base.OnInitializedAsync();
    }

    public async Task PrintDotNetObject()
    {
        var obj = new {
            FistName = "Jon",
            LastName = "Doe",
            Age = 27,
            BirthDate = DateTime.Now.AddYears(-27),
            LikesDotNet = true
        };
        await Js.InvokeVoidAsync("dotNetMauiApp.getMessage", _codeBlock, obj);
    }
}
更优双向通信实现方案

MAUI(C#)→ Vue(JS)

除了上述调用方式,还可以通过BlazorWebView的全局上下文传递数据,或者利用DotNetObjectReference实现更灵活的交互。

Vue(JS)→ MAUI(C#)

实现从Vue触发MAUI的C#方法:

  1. 在MAUI中创建供JS调用的服务类:
public class MauiCommunicationService
{
    private readonly MainPage _mainPage;

    public MauiCommunicationService(MainPage mainPage)
    {
        _mainPage = mainPage;
    }

    [JSInvokable]
    public void UpdateMauiEntry(string text)
    {
        _mainPage.Dispatcher.Dispatch(() =>
        {
            _mainPage.MauiEntry.Text = text;
        });
    }
}
  1. 在MainPage.xaml.cs中注册服务并传递给JS全局上下文:
protected override void OnInitialized()
{
    base.OnInitialized();
    var service = new MauiCommunicationService(this);
    BlazorWebView.JSGlobalObjectReference = DotNetObjectReference.Create(service);
}
  1. 在Vue中调用MAUI方法:
// 在Vue的方法中触发
callMauiMethod() {
    window.DotNet.invokeMethodAsync('MauiApp1', 'UpdateMauiEntry', '来自Vue的消息!');
}

内容的提问来源于stack exchange,提问作者Invix

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.02 02:10:16