ASP.NET Core MVC自定义HTML助手下拉框模型绑定失败求助
问题:ASP.NET Core MVC自定义下拉按钮控件无法绑定模型
问题原因
- 你使用了
type="button"的input控件,这类按钮的值不会随表单提交到后台,模型绑定自然无法获取到选中值 - 下拉项用的是
<li>标签,没有关联到可提交的表单控件,点击选项时也未更新用于提交的字段值 - 原代码存在多处语法错误:
dropdown未加引号、string.empty应为string.Empty、三元运算符写错(>替换为?)、调用BuildDropdownList时传的id变量未定义(应使用fieldId)
修正后的代码实现
BootstrapHtml.cs
using Microsoft.AspNetCore.Mvc.Rendering; using Microsoft.AspNetCore.Mvc.ViewFeatures; using System.IO; using System.Linq.Expressions; using System.Text.Encodings.Web; public static class BootstrapHtml { public static IHtmlContent BootstrapDropdownFor<TModel, TValue>( this IHtmlHelper<TModel> htmlHelper, Expression<Func<TModel, TValue>> expression, IEnumerable<SelectListItem> list) { var expressionHelper = htmlHelper.ViewContext.HttpContext.RequestServices.GetService(typeof(ModelExpressionProvider)) as ModelExpressionProvider; var fieldName = expressionHelper.GetExpressionText(expression); var fullBindingName = htmlHelper.ViewContext.ViewData.TemplateInfo.GetFullHtmlFieldName(fieldName); var fieldId = TagBuilder.CreateSanitizedId(fullBindingName, "-"); var metaData = expressionHelper.CreateModelExpression(htmlHelper.ViewData, expression); var selectedValue = metaData.Model?.ToString() ?? string.Empty; var selectedText = list.FirstOrDefault(item => item.Value == selectedValue)?.Text ?? "请选择"; // 隐藏输入框:负责提交选中值,是模型绑定的核心 var hiddenInput = new TagBuilder("input") { Attributes = { { "id", $"{fieldId}-hidden" }, { "name", fullBindingName }, { "type", "hidden" }, { "value", selectedValue } } }; // 下拉触发按钮:仅用于打开菜单,不参与表单提交 var dropdownButton = new TagBuilder("button") { Attributes = { { "id", fieldId }, { "type", "button" }, { "class", "btn btn-secondary dropdown-toggle" }, { "data-bs-toggle", "dropdown" }, { "aria-expanded", "false" } } }; dropdownButton.InnerHtml.Append(selectedText); var wrapper = new TagBuilder("div"); wrapper.AddCssClass("dropdown"); wrapper.InnerHtml.AppendHtml(hiddenInput); wrapper.InnerHtml.AppendHtml(dropdownButton); wrapper.InnerHtml.AppendHtml(BuildDropdownList(fieldId, list, selectedValue)); using (var writer = new StringWriter()) { wrapper.WriteTo(writer, HtmlEncoder.Default); return new HtmlString(writer.ToString()); } } private static TagBuilder BuildDropdownList(string buttonId, IEnumerable<SelectListItem> selectListItems, string selectedValue) { var ul = new TagBuilder("ul") { Attributes = { { "class", "dropdown-menu" }, { "aria-labelledby", buttonId } } }; foreach (var item in selectListItems) { if (item.Disabled) { var disabledLi = new TagBuilder("li"); disabledLi.InnerHtml.AppendHtml($"<span class=\"dropdown-item disabled\">{item.Text}</span>"); ul.InnerHtml.AppendHtml(disabledLi); continue; } var li = new TagBuilder("li"); var link = new TagBuilder("a") { Attributes = { { "class", $"dropdown-item {item.Value == selectedValue ? "active" : ""}" }, { "data-value", item.Value }, { "href", "#" } } }; link.InnerHtml.Append(item.Text); li.InnerHtml.AppendHtml(link); ul.InnerHtml.AppendHtml(li); } return ul; } }
前端交互脚本(添加到Test.cshtml或布局页)
<script> document.addEventListener('DOMContentLoaded', function() { // 监听下拉项点击,更新隐藏输入框和按钮文本 document.querySelectorAll('.dropdown-item[data-value]').forEach(item => { item.addEventListener('click', function(e) { e.preventDefault(); var value = this.getAttribute('data-value'); var text = this.textContent.trim(); var dropdown = this.closest('.dropdown'); // 更新绑定用的隐藏输入框值 dropdown.querySelector('input[type="hidden"]').value = value; // 更新按钮显示文本 dropdown.querySelector('.dropdown-toggle').textContent = text; // 切换选中项的active样式 dropdown.querySelectorAll('.dropdown-item').forEach(i => i.classList.remove('active')); this.classList.add('active'); }); }); }); </script>
修正说明
- 新增的隐藏输入框是模型绑定的关键,它的
name属性与模型字段完全一致,表单提交时会自动把值发送到后台 - 下拉触发按钮仅负责打开菜单,不再承担提交值的功能
- 下拉项改为
<a>标签并添加点击事件,点击时同步更新隐藏输入框的值和按钮显示文本,同时标记选中状态 - 修复了原代码中的所有语法错误
内容的提问来源于stack exchange,提问作者Eduwow
相关产品推荐
相关产品推荐

