.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组件的注入:
- 修改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); }
- 调整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已注入完成:
- 在
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(); } }
- 优化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#方法:
- 在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; }); } }
- 在
MainPage.xaml.cs中注册服务并传递给JS全局上下文:
protected override void OnInitialized() { base.OnInitialized(); var service = new MauiCommunicationService(this); BlazorWebView.JSGlobalObjectReference = DotNetObjectReference.Create(service); }
- 在Vue中调用MAUI方法:
// 在Vue的方法中触发 callMauiMethod() { window.DotNet.invokeMethodAsync('MauiApp1', 'UpdateMauiEntry', '来自Vue的消息!'); }
内容的提问来源于stack exchange,提问作者Invix
相关产品推荐
相关产品推荐

