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

Blazor MudBlazor多级子组件表单验证不触发问题排查

问题描述

使用Blazor MudBlazor v6.17.0,现有两级组件结构:

  • 基础组件CustomerComponent,包含MudAutocomplete用于选择客户名称
  • 容器组件CustomerTemplateComponent,包含EditForm并引用CustomerComponent

点击保存按钮时,表单未执行验证,API收到无效模型数据,且底层CustomerComponent的绑定未正常生效;但将CustomerComponent直接用于顶层表单时,验证功能正常。询问是否需要使用级联参数或存在其他问题。


相关代码

CustomerComponent

<div class="row" style="padding-top:10px;">
    <div class="col-4 mb-3">
        <MudAutocomplete id="name" For="@(() => Customer.Name)" T="string" Label="Name:" @bind-Value="Customer.Name" SearchFunc="@SearchCustomer" Margin="Margin.Dense" Dense="true" Variant="Variant.Outlined" />
    </div>
</div>

@code {
    [Parameter] public Customer Customer { get; set; }
    [Parameter] public IEnumerable<string> CustomerList { get; set; }
   
    private Task<IEnumerable<string>> SearchCustomer(string value)
    {
        if (string.IsNullOrEmpty(value))
        {
            Customer.Name = "";
            return Task.FromResult(CustomerList);
        }
        var filteredList = CustomerList.Where(x => x.Contains(value, StringComparison.InvariantCultureIgnoreCase));
        return Task.FromResult(filteredList);
    }
}

CustomerTemplateComponent

<EditForm Model="@Template" OnValidSubmit="@SaveEvent">
    <DataAnnotationsValidator/>
    <br />
    <div class="row" style="padding-top: 6px;">
        <div class="col-12">
            <MudTextField id="TemplateName" For="@(() => Template.TemplateName)" @bind-Value="@Template.TemplateName" 
                         Label="Template Name:" Variant="Variant.Outlined" Margin="Margin.Dense"></MudTextField>
        </div>
    </div>
    <CustomerComponent  CustomerList="@CustomerList" 
                         Customer="@Template.Customer" />
    
    <div class="row" style="padding-top:8px;">
        <div class="col-12 text-end mb-3">
            <button class="btn btn-primary" disabled="@Processing" id="Save-Button">Save</button>
            <div type="button" class="btn btn-secondary" @onclick="@CancelEvent" id="Cancel-Button">Cancel</div>
        </div>
    </div>
</EditForm>
@code {
    [Parameter] public bool Processing { get; set; }
    [Parameter] public Template Template { get; set; }
    [Parameter] public EventCallback CancelEvent { get; set; }
    [Parameter] public EventCallback SaveEvent { get; set; }
    [Parameter] public IEnumerable<string> CustomerList { get; set; }
}

顶层引用代码

<MudPaper Elevation="10">
    <MudGrid Class="d-flex align-content-center justify-center flex-grow-1 gap-4" Style="padding:10px;">
        <CustomerTemplateComponent CancelEvent="@Cancel" CustomerList="@Customers" 
                             SaveEvent="@Save" Processing="@Processing" Template="@_template" />
    </MudGrid>
</MudPaper> 

@code {
    private async Task Save()
    {
        Processing = true;

        try
        {
            await _templateService.SaveAsync(_template);
            ToastService.ShowSuccess("Template Updated.");
            NavigationManager.NavigateTo("/tradetemplates");
        }
        catch (Exception ex)
        {
            Logger.Error(ex, "Error saving templates.");
            ToastService.ShowError(ex.Message);
        }
        finally
        {
            Processing = false;
        }
    }
}

实体类定义

public class Template 
{
    public string TemplateName { get; set; }
    public Customer Customer { get; set; }
}

public class Customer 
{
    public string Name { get; set; }
}

解决方案

问题出在三个核心点:缺少验证规则定义、子组件输入控件未关联顶层表单验证上下文、保存按钮未明确触发表单提交流程,具体修复步骤如下:

1. 为实体类添加数据验证注解

验证需要基于明确规则触发,为实体类添加DataAnnotations验证特性:

using System.ComponentModel.DataAnnotations;

public class Template 
{
    [Required(ErrorMessage = "模板名称不能为空")]
    public string TemplateName { get; set; }
    
    [Required(ErrorMessage = "请选择客户")]
    public Customer Customer { get; set; }
}

public class Customer 
{
    [Required(ErrorMessage = "客户名称不能为空")]
    public string Name { get; set; }
}

2. 修正子组件验证关联问题

子组件CustomerComponent中的MudAutocomplete的For表达式指向自身参数,而非顶层Template模型的属性,导致验证上下文无法识别该字段。

修改CustomerComponent,新增表达式参数接收顶层模型的字段路径:

<div class="row" style="padding-top:10px;">
    <div class="col-4 mb-3">
        <MudAutocomplete id="name" For="@CustomerNameExpression" T="string" Label="Name:" @bind-Value="Customer.Name" SearchFunc="@SearchCustomer" Margin="Margin.Dense" Dense="true" Variant="Variant.Outlined" />
    </div>
</div>

@code {
    [Parameter] public Customer Customer { get; set; }
    [Parameter] public IEnumerable<string> CustomerList { get; set; }
    [Parameter] public Expression<Func<string>> CustomerNameExpression { get; set; }
   
    private Task<IEnumerable<string>> SearchCustomer(string value)
    {
        if (string.IsNullOrEmpty(value))
        {
            Customer.Name = "";
            return Task.FromResult(CustomerList);
        }
        var filteredList = CustomerList.Where(x => x.Contains(value, StringComparison.InvariantCultureIgnoreCase));
        return Task.FromResult(filteredList);
    }
}

在CustomerTemplateComponent引用CustomerComponent时,传入顶层模型的表达式:

<CustomerComponent  CustomerList="@CustomerList" 
                     Customer="@Template.Customer" 
                     CustomerNameExpression="@(() => Template.Customer.Name)" />

3. 明确设置保存按钮的提交类型

确保保存按钮触发EditForm的提交流程,为按钮添加type="submit"属性:

<button type="submit" class="btn btn-primary" disabled="@Processing" id="Save-Button">Save</button>

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.27 08:06:10