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

ASP.NET Core 7 MVC中复用自定义多选下拉框的方案求助

解决方案:ASP.NET Core 7 MVC 中Bootstrap 5搜索多选下拉的复用与模型绑定

一、用Editor Template实现组件复用+模型自动绑定

Editor Template完全适配你的场景,它能直接绑定主视图模型属性,自动同步选中值,复用性强,操作并不繁琐。

1. 创建Editor Template模板

在Views/Shared/EditorTemplates目录下新建DropDownOption.cshtml,代码如下:

@model YourNamespace.DropDownOption

<div class="dropdown bootstrap-multi-select" id="@ViewData.TemplateInfo.GetFullHtmlFieldName(string.Empty)">
    <button class="btn btn-secondary dropdown-toggle" type="button" data-bs-toggle="dropdown" aria-expanded="false">
        @Model.Title
    </button>
    <div class="dropdown-menu p-2">
        <input type="text" class="form-control mb-2" placeholder="搜索选项" oninput="filterDropdownOptions(this)">
        @foreach (var option in Model.Options)
        {
            <div class="form-check">
                <input class="form-check-input" 
                       type="checkbox" 
                       name="@ViewData.TemplateInfo.GetFullHtmlFieldName("SelectedValues")" 
                       value="@option.Value" 
                       @(Model.SelectedValues.Contains(option.Value) ? "checked" : "")>
                <label class="form-check-label">@option.Text</label>
            </div>
        }
    </div>
</div>

<script>
function filterDropdownOptions(input) {
    const filterText = input.value.toLowerCase();
    const optionItems = input.parentElement.querySelectorAll('.form-check');
    optionItems.forEach(item => {
        const labelText = item.querySelector('.form-check-label').textContent.toLowerCase();
        item.style.display = labelText.includes(filterText) ? 'block' : 'none';
    });
}
</script>

替换YourNamespace为实际命名空间,DropDownOption需包含Title(下拉标题)、Options(键值对集合)、SelectedValues(选中值集合)三个核心属性

2. 主视图中复用组件

在ExportView.cshtml里,直接用EditorFor调用模板:

@model YourNamespace.ExportViewModel

<div class="row g-3">
    <div class="col-md-6">
        @Html.EditorFor(m => m.Property1, "DropDownOption")
    </div>
    <div class="col-md-6">
        @Html.EditorFor(m => m.Property2, "DropDownOption")
    </div>
</div>

提交表单时,每个下拉框的选中值会自动同步到对应模型属性的SelectedValues集合,无需额外处理。

二、实现Ajax联动过滤

基于上述模板,添加联动逻辑即可实现Property1选值后过滤Property2的选项:

1. 后端写联动接口

在控制器中新增Action,接收Property1的选中值,返回过滤后的Property2选项:

[HttpPost]
[ValidateAntiForgeryToken]
public IActionResult GetFilteredProperty2Options(List<string> selectedProperty1Values)
{
    // 这里替换成你的业务逻辑:根据Property1选中值过滤Property2选项
    var filteredOptions = _yourDataService.GetProperty2Options(selectedProperty1Values);
    return Json(filteredOptions);
}

2. 修改模板添加联动监听

在DropDownOption.cshtml的脚本末尾添加选中监听逻辑:

<script>
// 监听当前下拉框的选中变化
document.querySelectorAll('#@ViewData.TemplateInfo.GetFullHtmlFieldName(string.Empty) input[type="checkbox"]').forEach(cb => {
    cb.addEventListener('change', function() {
        const selectedValues = Array.from(document.querySelectorAll('#@ViewData.TemplateInfo.GetFullHtmlFieldName(string.Empty) input[type="checkbox"]:checked'))
                                    .map(item => item.value);
        // 通过ViewData判断当前是否是Property1(主视图调用时传入标识)
        if ('@ViewData["IsTriggerDropdown"]' === "true") {
            fetch('/YourControllerName/GetFilteredProperty2Options', {
                method: 'POST',
                headers: {
                    'Content-Type': 'application/json',
                    'RequestVerificationToken': '@Html.AntiForgeryToken()'
                },
                body: JSON.stringify(selectedValues)
            })
            .then(res => res.json())
            .then(data => {
                // 更新Property2的下拉选项
                const targetDropdown = document.querySelector('#Property2 .dropdown-menu');
                // 清空原有选项(保留搜索框)
                targetDropdown.innerHTML = '<input type="text" class="form-control mb-2" placeholder="搜索选项" oninput="filterDropdownOptions(this)">';
                // 新增过滤后的选项
                data.forEach(opt => {
                    const optionDiv = document.createElement('div');
                    optionDiv.className = 'form-check';
                    optionDiv.innerHTML = `
                        <input class="form-check-input" type="checkbox" name="Property2.SelectedValues" value="${opt.Value}">
                        <label class="form-check-label">${opt.Text}</label>
                    `;
                    targetDropdown.appendChild(optionDiv);
                });
            });
        }
    });
});

// 保留之前的filterDropdownOptions函数
function filterDropdownOptions(input) {
    const filterText = input.value.toLowerCase();
    const optionItems = input.parentElement.querySelectorAll('.form-check');
    optionItems.forEach(item => {
        const labelText = item.querySelector('.form-check-label').textContent.toLowerCase();
        item.style.display = labelText.includes(filterText) ? 'block' : 'none';
    });
}
</script>

3. 主视图传递联动标识

调用Property1的模板时,通过ViewData传入标识:

@Html.EditorFor(m => m.Property1, "DropDownOption", new { IsTriggerDropdown = true })

三、为什么放弃View Components?

View Components是独立UI组件,拥有自身的模型上下文,无法直接绑定主视图的模型属性,所以不能自动同步主模型的选中值,这也是你之前遇到问题的核心原因。而Editor Template是专门为模型绑定设计的,完美匹配你的需求。

内容的提问来源于stack exchange,提问作者Rob K.

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.04 09:25:59