Blazor 表单怎么做?从简单 CRUD 到复杂业务表单的实现方式
AdminTable解决了列表表单这块框架直接沿用 BootstrapBlazor 的行为不定义EditTemplate时走 BootstrapBlazor 的自动表单生成定义了EditTemplate就完全用你的模板。这篇讲这两种方式分别怎么用、怎么选。一、自动表单与 EditTemplate默认与覆盖不定义EditTemplate时AdminTable的编辑弹窗走的是 BootstrapBlazor 的自动表单按实体上的[Display]、[Required]、[MaxLength]等注解自动生成字段和校验。一旦你定义了EditTemplate自动生成就被完全替换掉弹窗里的内容由你的 Razor 决定。也就是说这不是框架不支持自动表单而是默认自动需要时覆盖。AdminTable TItemProductEntity TKeylong EditDialogSizeSize.ExtraLarge ... TableColumns ... /TableColumns EditTemplate ProductEdit itemcontext / /EditTemplate /AdminTableEditTemplate里的context就是当前编辑的实体。用了它之后布局完全自由栅格、分组、标签页可以用任何组件框架自带的、BootstrapBlazor 的、第三方甚至自写的条件显示、联动、动态字段都是普通 C# 逻辑不需要学一套 DSL不需要为每种字段类型维护控件映射表。如果你不想手写字段又想要一个可编辑的起点代码生成器/Admin/CrudGenerator会把常见字段的样板 Razor 生成出来。它本质上是把自动表单的默认结果固化成一个可编辑的文件改起来没有额外心智负担。二、编辑弹窗的装配1. 弹窗底部按钮AdminTable会自动注入底部模板EditFooterTemplatecontext__builder{EditContextCaptureref_editContextCapture/if(EnableDraft){DropdownColorColor.SecondaryShowSplittrueTValueintItems(newListSelectedItem{new(5,5s),new(10,10s),new(20,20s),new(30,30s){ActiveDraftAutoSaveInterval30}}) OnClick(async () await ManualDraftSave())OnSelectedItemChanged(asyncitem{DraftAutoSaveIntervalint.Parse(item.Value);...})ButtonTemplateiclassfa-regular fa-floppy-disk/ispaniddraft-save-btnCommonLocalizer[草稿]/span/ButtonTemplate/Dropdown}DialogCloseButton/if(EnableSaveWithoutClose){Buttonref_saveButtonOnClick(async () await OnSaveWithoutClose(context))ColorColor.PrimaryText(CommonLocalizer[保存])Iconfa-solid fa-floppy-disk/}Buttonref_saveCloseButtonOnClick(async () await OnSaveAndCloseAsync(context))ColorColor.PrimaryText(CommonLocalizer[EnableSaveWithoutClose? 保存并关闭 : 保存])Iconfa-solid fa-check/};三个按钮的语义按钮出现条件行为草稿EnableDrafttrue手动保存草稿下拉可切自动保存间隔5/10/20/30 秒保存EnableSaveWithoutClosetrue保存后不关弹窗可以继续改/继续填下一条保存并关闭始终保存成功后刷新列表并关闭弹窗2. 保存前一定先校验privateasyncTaskOnSaveAndCloseAsync(TItemitem){if(_saving)return;_savingtrue;ApplySavingState(true);try{if(_editContextCapture?.Validate()!true){return;}varchangedTypeResolveChangedType(item);if(awaitOnSaveAsync!(item,changedType)){awaitMessageService.Success(CommonLocalizer[已保存]);...}}...}EditContextCapture的作用就是拿到ValidateForm下发的EditContext并手动触发校验/// summary/// 捕获 ValidateForm 下发的 EditContext以手动触发客户端验证。/// /summarypublicclassEditContextCapture:ComponentBase{[CascadingParameter]privateEditContextEditContext{get;set;}default!;publicEditContext?CurrentEditContextEditContext;/// summary触发客户端验证返回验证结果。/summarypublicboolValidate()EditContext?.Validate()??false;/// summary/// 重置验证状态标记所有字段为未修改。/// 在保存不关闭场景下使用避免旧验证状态残留。/// /summarypublicvoidResetValidation()EditContext?.MarkAsUnmodified();}所以数据注解是生效的实体上的[Required]、[MaxLength]、[Range]会在保存前被校验不通过就不落库。无论你用的是自动表单还是EditTemplate这套校验机制都一样。3. 增删改的类型判定保存时不能靠Id 0就是新增来判断——源码里有一个很实际的坑// 插入失败时 FreeSql 可能已为 [Snowflake] 主键回填了雪花 Id// 保存时若按 Id 是否为 0 推断变更类型会把重试误判成编辑。// 这里记录弹窗的真实类型保存时以此为准。if(optionisITableEditDialogOptionTItemeditDialogOption){_editDialogChangedTypeeditDialogOption.ItemChangedType;_editDialogChangedTypeCapturedtrue;}框架在弹窗打开时记录真实的变更类型保存时以它为准。自己写OnSaveAsync时也要注意这一点如果你用Id 0判断新增/编辑在插入失败后重试的场景下会出错。4. 保存中的按钮状态privatevoidApplySavingState(boolsaving){SetButtonSaving(_saveButton,saving,fa-solid fa-floppy-disk);SetButtonSaving(_saveCloseButton,saving,fa-solid fa-check);}保存和保存并关闭会同时进入 loading 并禁用避免用户连点两次造成重复提交。5. 保存不关闭新记录会切换到编辑态// 保存后对话框不关闭重新启动草稿自动保存if(EnableDraft){varoldDraftKey_draftKey;_draftKeyGetDraftKey(changedType,item);awaitJS.InvokeVoidAsync(EasyAdminBlazorJS.removeDraft,[oldDraftKey]);awaitJS.InvokeVoidAsync(EasyAdminBlazorJS.removeDraft,[_draftKey]);_lastSavedJsonnull;_restartDraftAfterClosetrue;}awaitCloseEditDialogAsync();_editDialogChangedTypeItemChangedType.Update;_editDialogChangedTypeCapturedtrue;awaitShowEditDialog(ItemChangedType.Update);细节值得注意新增保存成功后会以编辑态重新打开同一条记录而不是清空表单。这样用户能立刻看到刚保存的数据也能接着改。同时草稿键会从add迁移到edit_{id}旧草稿被清理。三、从最简单的表单开始不定义EditTemplate时你不需要写任何表单代码。框架会按实体注解自动生成。如果字段有特殊的布局或组件要求再用EditTemplate覆盖using ProductEntity EasyAdminBlazor.Test.Products.Product div classrow form-inline g-3 div classcol-12 col-sm-6 label classform-label产品名称/label input binditem.Title typetext classform-control maxlength100 / /div div classcol-12 col-sm-6 input binditem.Price typenumber step0.01 classform-control / /div div classcol-12 col-sm-6 Checkbox bind-Valueitem.IsOnSale DisplayText上架 / /div div classcol-12 col-sm-6 AdminFileInput bind-Valueitem.Image DisplayText产品图片 / /div div classcol-12 Textarea bind-Valueitem.Excerpt maxlength500/Textarea /div div classcol-12 AdminEditor bind-Valueitem.Content DisplayText产品详情 / /div /div code { [Parameter] [NotNull] public ProductEntity? item { get; set; } }原生input bind和 BootstrapBlazor 组件可以混用。区别在于写法是否参与 EditContext 校验说明input binditem.X否简单直接但[Required]等注解不会自动提示BootstrapInput bind-Valueitem.X是推荐能显示校验消息AdminFileInput bind-Value...是继承ValidateBasestring如果要让数据注解生效把字段换成 BootstrapBlazor 的输入组件或ValidateBase家族的组件即可。四、字段组件速查框架自带的后台字段组件参数以源码为准组件参数用途AdminFileInputbind-Value、DisplayText文件路径 选择器 图片预览AdminEditorbind-Value、DisplayText富文本未装 HtmlEditor 扩展时是普通文本框AdminDictSelectbind-Value、ParentName必填、CacheDuration默认 30 秒字典单选AdminDictMultiSelectbind-Value、ParentName、CacheDuration字典多选AdminMultiSelectTItem、bind-Value、GetText、Where、UseDataPermission实体多选弹窗表格AdminSelectEntityTItem、TKey、bind-Value、GetText、Where、UseDataPermission实体单选AdminSelectTableTItem、bind-Value/bind-ValueId、GetText、TableColumns实体单选列可定制AdminTreeTItem、bind-Value、GetText、Where、SortString树形选择组织、菜单AdminCheckboxListGenericTItem、TValue、Items、bind-Value复选框列表示例字典 实体选择 富文本的组合div classrow form-inline g-3 div classcol-12 col-sm-6 AdminDictSelect bind-ValueModel.OrderType ParentNameorder_type DisplayText订单类型 / /div div classcol-12 col-sm-6 AdminSelectEntity TItemSysUser TKeylong bind-ValueIdModel.OwnerId GetTextu u.Nickname UseDataPermissiontrue DisplayText负责人 / /div div classcol-12 AdminEditor bind-ValueModel.Remark DisplayText备注 / /div /div关于字典缓存要有个预期CacheDuration默认 30 秒字典项改动后最多 30 秒生效如果是长时间打开的标签页可能需要手动刷新页面。五、复杂表单的三种组织方式1. 标签页分组字段多的时候用Tab分组这是仓库里的真实做法inject CommonLocalizer CommonLocalizer Tab IsCard TabItem TextCommonLocalizer[随笔] !-- 主体字段专栏、标题、类型、关键字 -- /TabItem TabItem TextCommonLocalizer[设置] !-- 浏览量、评论数、推荐、置顶等 -- /TabItem TabItem TextCommonLocalizer[审批] ApprovalActions TItemArticle BillModel OnChangedOnApprovalChanged / /TabItem /Tab把审批面板放进一个 Tab是接入审批模块最自然的方式见第 16 篇。2. 条件显示条件显示就是普通的if不需要额外机制Select bind-ValueModel.OrderType ItemsorderTypes / if (Model.OrderType custom) { BootstrapInput bind-ValueModel.CustomNote DisplayText自定义说明 / }更复杂的联动选 A 自动填 B就在OnValueChanged里改数据并StateHasChanged()privateasyncTaskOnOwnerChanged(long?userId){Model.OwnerIduserId;if(userIdis0){varuserawaitrepo.Select.Where(xx.IduserId).FirstAsync();Model.OwnerNameuser?.Nickname??string.Empty;}awaitInvokeAsync(StateHasChanged);}3. 大表单拆组件字段特别多时把一组字段拆成一个子组件用[Parameter]传实体// OwnerSection.razor[Parameter][NotNull]publicOrder?Model{get;set;}这样每个文件保持在可读的规模也便于多人协作。六、保存前后的业务校验客户端校验之外服务端还要有业务校验写在OnBeforeSaveAsyncprivateasyncTaskOnBeforeSaveAsync(AdminSaveEventArgsSysUsere){if(await_repo.Select.Where(aa.Usernamee.Item.Usernamea.Id!e.Item.Id).AnyAsync()){awaitSwalService.Error(CommonLocalizer[用户名已存在]);e.Canceltrue;// 取消保存}}publicclassAdminSaveEventArgsTItemwhereTItem:class{publicItemChangedTypeChangedType{get;set;}publicrequiredTItemItem{get;set;}publicboolCancel{get;set;}}OnBeforeSaveAsync里可以做唯一性校验、跨字段校验、根据输入补全派生字段、按需修改e.Item。设置e.Cancel true就中止保存。保存成功后OnFinishSaveAsync适合做副作用发通知、写审计、触发审批提交、刷新关联数据。七、性能与体验建议大表单不要把所有关联数据都在弹窗打开时加载。用AdminSelectEntity这类用时才弹窗的组件比一次性加载几千条选项要好。富文本字段注意体积。AdminEditor绑定的是 HTML 字符串长正文会让草稿序列化和网络传输变重草稿自动保存间隔不宜太短。EnableSaveWithoutCloseEnableDraft组合适合连续录入场景比如录入一批商品。EditDialogSize按字段数量选Medium/Large/ExtraLarge标签页表单一般用ExtraLarge。保存中禁用按钮框架已做比乐观更新更适合后台用户能确定数据是否真的写进去了。八、常见问题现象原因处理编辑弹窗里字段是自动生成的没有定义EditTemplate这是默认行为要自定义就加EditTemplate必填校验不显示用了原生input而不是 BootstrapBlazor 组件换成BootstrapInput/ValidateBase家族点了保存没反应校验没过Validate()返回 false看字段上的校验提示新增后变成了编辑态EnableSaveWithoutClose的预期行为这是设计如此不需要就不开这个开关保存失败后重新保存变成编辑按Id判断变更类型用框架的变更类型捕获或按自己的标志位判断关联下拉为空字典/实体无数据或数据权限过滤掉了检查字典分类、实体数据、UseDataPermission草稿恢复提示一直弹草稿键有残留框架会在保存后清理自定义逻辑不要复用同一个键九、小结EasyAdminBlazor 的表单设计可以概括成一句话默认走 BootstrapBlazor 的自动表单需要时用EditTemplate覆盖弹窗、校验、保存、草稿、权限这些通用部分框架替你做好。关注点由谁负责自动表单框架不定义EditTemplate时按实体注解生成弹窗、按钮、loading框架EditFooterTemplateApplySavingState校验触发框架EditContextCapture.Validate()校验规则实体的数据注解 BootstrapBlazor 输入组件字段与布局页面EditTemplate可选业务校验页面OnBeforeSaveAsync保存后副作用页面OnFinishSaveAsync草稿框架EnableDraft可调间隔如果你正在用 .NET 10 Blazor 做后台表单是最花时间的部分。EasyAdminBlazor 默认给你自动表单复杂业务表单可以在EditTemplate里自由发挥保存、校验、草稿这些通用机制框架已经替你做好了。文档https://easyadmin.wang-zhan.com.cn/doc源码https://gitee.com/gudufy/EasyAdminBlazor

相关新闻

高温热管与普通热管怎么选?温度段选型逻辑详解

高温热管与普通热管怎么选?温度段选型逻辑详解

高温热管与普通热管怎么选?温度段选型逻辑详解 摘要:热管的选型首先需要确定工作温度段,不同温度段对应的工质类型、壳体材料、传热能力和成本水平差异显著。本文提供一个按温度分段的选型框架,帮助工程师快速定位适合特定应用的…

2026/10/8 23:43:27 阅读更多 →
NeMo Guardrails 预置护栏库(Library)完全指南:内置 Rail 目录、激活方式与贡献新 Rail 的录制测试规范

NeMo Guardrails 预置护栏库(Library)完全指南:内置 Rail 目录、激活方式与贡献新 Rail 的录制测试规范

人工智能大模型AI 安全治理模型安全内容安全提示词注入防护RAG 【免费下载链接】Guardrails NeMo Guardrails is an open-source toolkit for easily adding programmable guardrails to LLM-based conversational systems. 项目地址: https://gitcode.com/gh_mirro…

2026/10/8 23:40:42 阅读更多 →
AI Agent_11 AI Agent 上下文工程(Context Engineering)

AI Agent_11 AI Agent 上下文工程(Context Engineering)

下面先看张机制图,再逐节展开。一、先建立直觉:什么是上下文工程上下文(Context) 模型每次请求时 "看到" 的全部内容 —— 系统提示词、用户消息、工具结果、检索资料、历史对话…… 全都在上下文窗口里。上下文工程&a…

2026/10/8 23:40:40 阅读更多 →

最新新闻

Nacos 2.4.0 Oracle迁移:重写数据访问层实现信创兼容

Nacos 2.4.0 Oracle迁移:重写数据访问层实现信创兼容

简介:本资源是针对 Nacos 2.4.0 官方版本深度定制的 Oracle 数据库适配版,面向微服务架构中需将 Nacos 注册中心与配置中心持久化至 Oracle 生产环境的 Java 开发者及中间件运维人员。改造覆盖数据库驱动、SQL 脚本、启动脚本及核心配置项,支…

2026/10/9 13:26:12 阅读更多 →
门窗配件---认识玻璃之挑选篇

门窗配件---认识玻璃之挑选篇

门窗配件---认识玻璃之挑选篇01 因地制宜这里的“地”有两方面的意思,一个是广义上的气候区域,一方水土养一方人,足见每个地方的特色,生活习惯的迥异;二来则是我们门窗应用的具体空间。中国之大,涵盖了五个…

2026/10/9 13:26:12 阅读更多 →
PLSQL Developer免Oracle客户端部署实战指南

PLSQL Developer免Oracle客户端部署实战指南

简介:本资源为免Oracle客户端版PLSQL Developer绿色安装包,面向Oracle数据库开发人员、DBA及学习PL/SQL编程的中初级开发者,解决本地无完整Oracle客户端环境仍需高效编写、调试与管理PL/SQL代码的核心痛点。压缩包共524个文件,总计…

2026/10/9 13:26:12 阅读更多 →
医院病房管理系统数据库设计:表结构、SQL与事务实践

医院病房管理系统数据库设计:表结构、SQL与事务实践

简介:面向数据库课程设计与医院业务流程管理的实战型项目,适合计算机相关专业学生在数据库原理、软件工程等课程实训中使用,完整覆盖医院病房管理场景。压缩包共146个文件,约5.04MB,包含Java源码与class文件&#xff0…

2026/10/9 13:26:12 阅读更多 →
Meta开放式机架V3电源架结构参考设计(3kW PSU+18kW PowerShelf+PMI)

Meta开放式机架V3电源架结构参考设计(3kW PSU+18kW PowerShelf+PMI)

Open Rack V3 电源系统组成(3 kW PSU+18 kW Power ShelfPMI) 文档图纸(2D pdf3D stp)已上传至星球:https://t.zsxq.com/lwEeT 或知识星球搜索星球号:54295154 项目 内容 组成 ① Power Sh…

2026/10/9 13:26:12 阅读更多 →
英语语法术语表:用“人话”拆解句子骨架与从句逻辑

英语语法术语表:用“人话”拆解句子骨架与从句逻辑

1. 为什么你需要一份语法术语表,而不是又一本语法书很多人学英语学到某个阶段会撞上一堵墙:句子里的单词都认识,但就是看不懂它在说什么。你去查语法书,书里告诉你这叫“非限制性定语从句”,你翻回目录找“定语从句”的…

2026/10/9 13:25:12 阅读更多 →

日新闻

Java时间API实战:LocalDate、Date与ZonedDateTime的转换与避坑指南

Java时间API实战:LocalDate、Date与ZonedDateTime的转换与避坑指南

Java时间API这个话题,隔三差五就会在群里被翻出来讨论一次。上周还有个同事线上处理一个订单超时问题,排查到最后发现是ZonedDateTime序列化后时区丢了,用户在下单当天晚上看到的时间整整差了8个小时。这类问题几乎每个做Java开发的人都遇到过…

2026/10/9 0:00:49 阅读更多 →
EasyTier实践:从NAT穿透到子网代理的异地组网部署与排错

EasyTier实践:从NAT穿透到子网代理的异地组网部署与排错

前几个月我手头有好几台机器需要互相访问:办公室台式机、家里 NAS、还有一台云主机。如果只是偶尔传个文件倒还好,问题是工作场景经常要在几处环境之间来回切换,每次都先登录跳板机再层层代理,实在折腾。我先后试过端口映射、自建…

2026/10/9 0:00:49 阅读更多 →
AI Agent工程实战:从七要素到七个决策点的系统设计指南

AI Agent工程实战:从七要素到七个决策点的系统设计指南

AI Agent 这个词在过去一年里被反复提及,但真正动手搭过一套能跑起来的 Agent 系统的人都知道,从"知道它是什么"到"让它稳定干活"之间隔着一整套工程决策。我前后参与过几个 Agent 项目的落地,从最初用现成框架拼装&…

2026/10/9 0:01:50 阅读更多 →

周新闻

KT148A语音芯片外挂8002D功放的工程实践指南

KT148A语音芯片外挂8002D功放的工程实践指南

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/8 15:26:32 阅读更多 →
LLC谐振变换器增益公式推导:从FHA等效到完整归一化表达式

LLC谐振变换器增益公式推导:从FHA等效到完整归一化表达式

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/8 15:26:40 阅读更多 →
ARM架构深度解析:从RISC设计理念到交叉编译实战

ARM架构深度解析:从RISC设计理念到交叉编译实战

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/9 10:11:06 阅读更多 →

月新闻

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/8 21:13:17 阅读更多 →
Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/8 15:26:17 阅读更多 →
黑夜航拍船只数据集训练YOLOV5模型全流程解析

黑夜航拍船只数据集训练YOLOV5模型全流程解析

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/9 6:17:20 阅读更多 →