如何在MAUI/Blazor混合应用中调用MudBlazor模态对话框
实现MAUI中调用Razor类库的MudBlazor模态对话框
问题背景
我有一个MAUI XAML页面,希望点击按钮时显示位于Razor类库中的MudBlazor模态对话框,使其在MAUI应用中作为真实模态对话框呈现。已在MAUI应用的MainLayout页面中完成相关声明,目前尝试通过以下代码调用对话框,寻求可行实现方案:
按钮XAML代码
<buttons:SfButton x:Name="button" Text="Button" Clicked="OpenBlazorWebViewAsync" />
对话框调用逻辑代码
private async Task OpenBlazorWebViewAsync(object sender, EventArgs e) { try { var options = new MudBlazor.DialogOptions() { FullWidth = true, MaxWidth = MaxWidth.ExtraLarge, DisableBackdropClick = true, Position = DialogPosition.Center, CloseOnEscapeKey = false }; var dialog = await _dialogService.ShowAsync<SendMessageDialog>("Send Single Message", options); var result = await dialog.Result; if (result != null) { int secondsToVibrate = Random.Shared.Next(1, 7); TimeSpan vibrationLength = TimeSpan.FromSeconds(secondsToVibrate); Vibration.Default.Vibrate(vibrationLength); HapticFeedback.Perform(HapticFeedbackType.LongPress); await Task.Delay(1000); var duration = ToastDuration.Long; double fontSize = 14; var toast = Toast.Make("Message Sent Successfully", duration, fontSize); await toast.Show(); } } catch (Exception ex) { var duration = ToastDuration.Long; double fontSize = 14; var toast = Toast.Make($"Error: {ex.Message}", duration, fontSize); await toast.Show(); } }
Razor类库中的对话框页面代码
@using Microsoft.AspNetCore.Components.Forms @using Blazored.FluentValidation @using Syncfusion.Blazor.Calendars @inject IUsersService userService @inject IDapperContrib _dapperContrib @inject SweetAlertService Swal; <MudDialog> <DialogContent> <EditForm Model="@model"> <MudSelect class="my-4" @bind-Value="model.FirebaseDeviceId" Label="Users"> @foreach (var user in users) { if (!string.IsNullOrEmpty(user.FirebaseDeviceId)) { <MudSelectItem Value="@user.FirebaseDeviceId">@($"{user.FirstName} {user.LastName}")</MudSelectItem> } } </MudSelect> <MudSelect class="my-4" @bind-Value="model.EventName" Label="Event Name"> <MudSelectItem Value="@("Calendar")">Calendar</MudSelectItem> <MudSelectItem Value="@("Word")">Word</MudSelectItem> <MudSelectItem Value="@("Roster")">Roster</MudSelectItem> </MudSelect> <MudTextField @bind-Value="model.Title" Label="Title" /> <MudTextField @bind-Value="model.Message" Label="Message" /> </EditForm> </DialogContent> <DialogActions> <MudButton OnClick="Cancel">Cancel</MudButton> <MudButton Color="MudBlazor.Color.Primary" Disabled="@(!IsFormValid())" OnClick="Submit">Send Message</MudButton> </DialogActions> </MudDialog> @code { public List<User> users { get; set; } = new List<User>(); public NotificationModel model { get; set; } = new NotificationModel(); [CascadingParameter] MudDialogInstance MudDialog { get; set; } protected override async Task OnInitializedAsync() { users = (List<User>)await _dapperContrib.GetAll<User>(); } private void Cancel() { MudDialog.Cancel(); } private async void Submit() { await userService.SendSpecificUserTestMessage(model); await Swal.FireAsync(new SweetAlertOptions { Title = "Success!", TitleText = @$"Message Sent Successfully to user {model.FirebaseDeviceId}", Timer = 3000, ShowConfirmButton = false, Icon = "success", HeightAuto = false }); MudDialog.Close(); } private bool IsFormValid() { return !string.IsNullOrEmpty(model.FirebaseDeviceId) && !string.IsNullOrEmpty(model.EventName) && !string.IsNullOrEmpty(model.Title) && !string.IsNullOrEmpty(model.Message); } private void OnValueChanged() { } }
可行实现方案
1. 确认核心依赖配置
- 确保MAUI项目已安装
MudBlazor和Microsoft.AspNetCore.Components.WebView.MauiNuGet包,Razor类库已引用MudBlazor。 - 在MAUI项目的
MainLayout.razor中必须添加MudDialogProvider组件(MudBlazor对话框的核心依赖):
@inherits LayoutComponentBase <MudThemeProvider /> <MudDialogProvider /> <MudSnackbarProvider /> <div class="page"> <div class="sidebar"> <NavMenu /> </div> <main> <div class="top-row px-4"> <a href="https://learn.microsoft.com/aspnet/core/" target="_blank">About</a> </div> <article class="content px-4"> @Body </article> </main> </div>
2. 解决上下文适配问题
MAUI的XAML后台代码不在Blazor组件上下文内,无法直接注入IDialogService,推荐两种解决方式:
方案A:将触发逻辑移到Blazor组件(推荐)
把XAML按钮替换为Blazor组件内的按钮,直接在Blazor上下文调用对话框:
<!-- 新建MessageDialogTrigger.razor组件 --> @inject IDialogService DialogService <MudButton OnClick="OpenDialogAsync" Variant="Variant.Filled">打开对话框</MudButton> @code { private async Task OpenDialogAsync() { try { var options = new MudBlazor.DialogOptions() { FullWidth = true, MaxWidth = MaxWidth.ExtraLarge, DisableBackdropClick = true, Position = DialogPosition.Center, CloseOnEscapeKey = false }; var dialog = await DialogService.ShowAsync<SendMessageDialog>("Send Single Message", options); var result = await dialog.Result; if (!result.Canceled) { int secondsToVibrate = Random.Shared.Next(1, 7); await Vibration.Default.VibrateAsync(TimeSpan.FromSeconds(secondsToVibrate)); HapticFeedback.Perform(HapticFeedbackType.LongPress); await Task.Delay(1000); var toast = Toast.Make("Message Sent Successfully", ToastDuration.Long, 14); await toast.Show(); } } catch (Exception ex) { var toast = Toast.Make($"Error: {ex.Message}", ToastDuration.Long, 14); await toast.Show(); } } }
然后在XAML页面中通过BlazorWebView引用该组件:
<BlazorWebView HostPage="wwwroot/index.html"> <BlazorWebView.RootComponents> <RootComponent Selector="#app" ComponentType="{x:Type local:MessageDialogTrigger}" /> </BlazorWebView.RootComponents> </BlazorWebView>
方案B:在XAML后台获取Blazor服务
若必须保留XAML按钮,需在MauiProgram.cs中将IDialogService注册为单例:
builder.Services.AddMudServices(); builder.Services.AddSingleton<IDialogService>(sp => sp.GetRequiredService<MudDialogService>());
然后在XAML后台构造函数中注入:
private readonly IDialogService _dialogService; public YourXamlPage(IDialogService dialogService) { InitializeComponent(); _dialogService = dialogService; }
注意:需确保BlazorWebView已完成初始化,否则可能无法获取有效上下文。
3. 修正对话框异步方法问题
对话框的Submit方法使用async void会导致异常无法被捕获,改为async Task并返回明确结果:
private async Task Submit() { await userService.SendSpecificUserTestMessage(model); await Swal.FireAsync(new SweetAlertOptions { Title = "Success!", TitleText = @$"Message Sent Successfully to user {model.FirebaseDeviceId}", Timer = 3000, ShowConfirmButton = false, Icon = "success", HeightAuto = false }); MudDialog.Close(DialogResult.Ok(true)); }
4. 确保Razor类库组件可访问
检查Razor类库项目文件的目标框架设置,并确保组件为公共访问级别:
<Project Sdk="Microsoft.NET.Sdk.Razor"> <PropertyGroup> <TargetFrameworks>net7.0;net8.0</TargetFrameworks> <Nullable>enable</Nullable> <ImplicitUsings>enable</ImplicitUsings> </PropertyGroup> <ItemGroup> <PackageReference Include="MudBlazor" Version="最新版本号" /> </ItemGroup> </Project>
内容的提问来源于stack exchange,提问作者CodeMan03
相关产品推荐
相关产品推荐

