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

如何在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.Maui NuGet包,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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.24 00:44:53