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

Blazor Wasm/Server中不使用EditForm的表单验证方案求助

Blazor 原生/轻量实现带验证的多选下拉框与富文本编辑器

一、原生集成验证的多选下拉框

基于Blazor内置的InputBase<T>自定义组件,天然兼容EditForm的DataAnnotations验证,无需依赖第三方库。如果需要样式美化,可添加轻量JS做UI交互(不影响数据绑定与验证逻辑)。

自定义多选组件代码(MultiSelect.razor)

@typeparam TValue
@inherits InputBase<List<TValue>>

<div class="multi-select">
    <label>@Label</label>
    @foreach (var option in Options)
    {
        <div class="option-item">
            <input type="checkbox" 
                   id="option-@option.GetHashCode()"
                   checked="@CurrentValue.Contains(option)"
                   @onchange="(e) => ToggleSelection(option, e.Value)" />
            <label for="option-@option.GetHashCode()">@(OptionLabelFunc?.Invoke(option) ?? option.ToString())</label>
        </div>
    }
    <ValidationMessage For="@ValueExpression" />
</div>

@code {
    [Parameter] public string Label { get; set; }
    [Parameter] public IEnumerable<TValue> Options { get; set; } = Enumerable.Empty<TValue>();
    [Parameter] public Func<TValue, string> OptionLabelFunc { get; set; }

    private void ToggleSelection(TValue option, object isChecked)
    {
        var newValue = new List<TValue>(CurrentValue);
        if ((bool)isChecked)
        {
            if (!newValue.Contains(option))
                newValue.Add(option);
        }
        else
        {
            newValue.Remove(option);
        }
        CurrentValue = newValue;
    }

    protected override bool TryParseValueFromString(string value, out List<TValue> result, out string validationErrorMessage)
    {
        // 直接通过checkbox绑定数据,此方法不会触发,返回默认值即可
        result = CurrentValue;
        validationErrorMessage = null;
        return true;
    }
}

使用示例(集成EditForm与验证)

<EditForm Model="@userModel" OnValidSubmit="@HandleSubmit">
    <DataAnnotationsValidator />
    <ValidationSummary />

    <MultiSelect Label="选择兴趣爱好"
                 Options="@hobbyOptions"
                 @bind-Value="@userModel.SelectedHobbies" />

    <button type="submit">提交</button>
</EditForm>

@code {
    private List<string> hobbyOptions = new() { "阅读", "运动", "编程", "旅行" };
    private UserModel userModel = new();

    private void HandleSubmit()
    {
        // 处理表单提交逻辑
    }

    public class UserModel
    {
        [Required(ErrorMessage = "请至少选择一个兴趣爱好")]
        [MinLength(1, ErrorMessage = "请至少选择一个兴趣爱好")]
        public List<string> SelectedHobbies { get; set; } = new();
    }
}

二、集成EditForm验证的富文本编辑器(以Summernote为例)

通过封装InputBase<string>组件,结合IJSRuntime与JS编辑器交互,同时保留Blazor的验证机制,无需依赖第三方UI库。

自定义富文本编辑器组件(SummernoteEditor.razor)

@inherits InputBase<string>
@inject IJSRuntime JSRuntime

<div class="summernote-container">
    <label>@Label</label>
    <div @ref="@editorRef" class="summernote"></div>
    <ValidationMessage For="@ValueExpression" />
</div>

@code {
    [Parameter] public string Label { get; set; }
    private ElementReference editorRef;

    protected override async Task OnAfterRenderAsync(bool firstRender)
    {
        if (firstRender)
        {
            // 初始化Summernote并绑定回调
            await JSRuntime.InvokeVoidAsync("initSummernote", editorRef, CurrentValue, DotNetObjectReference.Create(this));
        }
        else if (CurrentValue != await JSRuntime.InvokeAsync<string>("getSummernoteContent", editorRef))
        {
            // 同步Blazor模型值到编辑器
            await JSRuntime.InvokeVoidAsync("setSummernoteContent", editorRef, CurrentValue);
        }
    }

    [JSInvokable]
    public void OnContentChanged(string content)
    {
        // 编辑器内容变化时更新Blazor绑定值
        CurrentValueAsString = content;
    }

    protected override bool TryParseValueFromString(string value, out string result, out string validationErrorMessage)
    {
        result = value;
        validationErrorMessage = null;
        return true;
    }
}

配套JS代码(wwwroot/js/summernote.js)

function initSummernote(element, initialContent, dotNetRef) {
    $(element).summernote({
        height: 200,
        callbacks: {
            onChange: function(contents) {
                dotNetRef.invokeMethodAsync('OnContentChanged', contents);
            }
        }
    });
    $(element).summernote('code', initialContent);
}

function getSummernoteContent(element) {
    return $(element).summernote('code');
}

function setSummernoteContent(element, content) {
    $(element).summernote('code', content);
}

使用示例(集成EditForm与验证)

<EditForm Model="@postModel" OnValidSubmit="@HandlePublish">
    <DataAnnotationsValidator />
    <ValidationSummary />

    <SummernoteEditor Label="文章内容" @bind-Value="@postModel.Content" />

    <button type="submit">发布文章</button>
</EditForm>

@code {
    private PostModel postModel = new();

    private void HandlePublish()
    {
        // 处理文章发布逻辑
    }

    public class PostModel
    {
        [Required(ErrorMessage = "请填写文章内容")]
        [MinLength(10, ErrorMessage = "内容长度不能少于10个字符")]
        public string Content { get; set; }
    }
}

核心思路总结

所有自定义控件通过继承InputBase<T>实现,这是Blazor原生集成EditForm验证系统的标准方式:

  1. 组件自动继承验证状态管理,无需手动处理验证触发与错误展示
  2. 数据双向绑定逻辑通过CurrentValue/CurrentValueAsString统一处理
  3. JS仅负责UI交互或编辑器初始化,核心数据与验证逻辑由Blazor控制

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.15 02:32:02