0

我在一个项目中工作,我需要从一系列模型值创建一个复选框列表,然后在发布时从控制器中检索值。不幸的是,未选中的复选框根本不会在发布时发送到表单集合,并且测试每个是否为 null 会导致代码笨拙和笨拙。但事实证明,为每个 SelectListItem 的文本和值添加隐藏字段使得在发布时抓取选定的值变得很容易,因此我构建了一些我在网上找到的代码,用于通过 TagHelper 创建一个复选框列表。效果很好,我已经包含注释来展示如何在视图中使用 TagHelper、如何注册它以及如何在控制器中收集选定的值。希望它可以帮助别人。

4

1 回答 1

0
/// <summary>
/// Creates a checkbox list that can be easily accessed in the model. 
/// <para>Example use in view: <checkboxlist asp-items="@Model.SomeSelectList" asp-model-name="SomeSelectList" asp-container="ul" asp-item="li"></checkboxlist></para>
/// <para>Example registration in _ViewImports file: @addTagHelper *, SomeNamespace</para>
/// <para>Example of retrieving selected values from model: model.SomeSelectList.Where(sl => sl.Selected == true).Select(sl => sl.Value).ToList()</para>
/// </summary>
[HtmlTargetElement("checkboxlist", Attributes = "asp-items, asp-model-name, asp-container, asp-item")]
public class CheckboxListTagHelper : TagHelper
{
    [HtmlAttributeName("asp-items")]
    public IEnumerable<SelectListItem> Items { get; set; }

    [HtmlAttributeName("asp-model-name")]
    public string ModelName { get; set; }

    [HtmlAttributeName("asp-container")]
    public string Container { get; set; }

    private string _containerId;
    [HtmlAttributeName("asp-container-id")]
    public string ContainerId 
    {
        get { return !string.IsNullOrWhiteSpace(_containerId) ? $"id=\"{_containerId}\"" : ""; }
        set { _containerId = value; } 
    }

    private string _containerName;
    [HtmlAttributeName("asp-container-name")]
    public string ContainerName 
    {
        get { return !string.IsNullOrWhiteSpace(_containerName) ? $"name=\"{_containerName}\"" : ""; }
        set { _containerName = value; }
    }

    private string _containerClass;
    [HtmlAttributeName("asp-container-class")]
    public string ContainerClass
    {
        get { return !string.IsNullOrWhiteSpace(_containerClass) ? $"class=\"{_containerClass}\"" : ""; }
        set { _containerClass = value; }
    }

    [HtmlAttributeName("asp-item")]
    public string Item { get; set; }

    private string _itemId;
    [HtmlAttributeName("asp-item-id")]
    public string ItemId
    {
        get { return !string.IsNullOrWhiteSpace(_itemId) ? $"id=\"{_itemId}\"" : ""; }
        set { _itemId = value; }
    }

    private string _itemName;
    [HtmlAttributeName("asp-item-name")]
    public string ItemName
    {
        get { return !string.IsNullOrWhiteSpace(_itemName) ? $"id=\"{_itemName}\"" : ""; }
        set { _itemName = value; }
    }

    private string _itemClass;
    [HtmlAttributeName("asp-item-class")]
    public string ItemClass
    {
        get { return !string.IsNullOrWhiteSpace(_itemClass) ? $"id=\"{_itemClass}\"" : ""; }
        set { _itemClass = value; }
    }

    public override void Process(TagHelperContext context, TagHelperOutput output)
    {
        var sb = new StringBuilder();

        sb.Append($@"<{Container} {ContainerId} {ContainerName} {ContainerClass}>");

        var index = 0;
        foreach (var item in Items)
        {
            var selected = item.Selected ? @"checked=""checked""" : "";
            var disabled = item.Disabled ? @"disabled=""disabled""" : "";

            sb.Append($@"<{Item} {ItemId} {ItemName} {ItemClass}>");
            sb.Append($@"<input type=""checkbox"" {selected} {disabled} id=""{ModelName}_{index}__Selected"" name=""{ModelName}[{index}].Selected"" value=""true"" /> ");
            sb.Append($@"<label for=""{ModelName}_{index}__Selected"">{item.Text}</label>");
            sb.Append($@"<input type=""hidden"" id=""{ModelName}_{index}__Text"" name=""{ModelName}[{index}].Text"" value=""{item.Text}"">");
            sb.Append($@"<input type=""hidden"" id=""{ModelName}_{index}__Value"" name=""{ModelName}[{index}].Value"" value=""{item.Value}"">");
            sb.Append($@"</{Item}>");

            index++;
        }

        sb.Append($@"</{Container}>");

        output.Content.AppendHtml(sb.ToString());
    }
}

我的新项目使用完整的 .NET Framework,由于某种原因不支持 TagHelpers,因此我为 SelectListItem 集合创建了一个扩展方法。这是我在上面发布的 TagHelper 类的精简版本,因为我不需要所有的花里胡哨。我正在使用 Bootstrap 3.4.1 在使用此扩展方法的页面上搭建脚手架,因此我使用了带有“form-check”类的 div 的默认容器。这是扩展方法的代码:

public static string GenerateCheckboxList(this List<SelectListItem> selectListItems, string modelName)
    {
        var sb = new StringBuilder();

        var index = 0;
        foreach (var item in selectListItems)
        {
            var selected = item.Selected ? @"checked=""checked""" : "";
            var disabled = item.Disabled ? @"disabled=""disabled""" : "";

            sb.Append($@"<div class=""form-check"">");

            sb.Append($@"<label for=""{modelName}_{index}__Selected"">{item.Text}</label> ");
            sb.Append($@"<input type=""checkbox"" {selected} {disabled} id=""{modelName}_{index}__Selected"" name=""{modelName}[{index}].Selected"" value=""true"" class=""form-check-input"" />");
            sb.Append($@"<input type=""hidden"" id=""{modelName}_{index}__Text"" name=""{modelName}[{index}].Text"" value=""{item.Text}"">");
            sb.Append($@"<input type=""hidden"" id=""{modelName}_{index}__Value"" name=""{modelName}[{index}].Value"" value=""{item.Value}"">");

            sb.Append($@"</div>");

            index++;
        }

        return sb.ToString();
    }

我忘了提...在视图中渲染生成的字符串时,您需要包含一个渲染原始内容的调用,否则渲染引擎将对 HTML 进行编码,它会看起来很奇怪。这就是视图中所需的全部内容:

@Html.Raw(Model.CheckboxList)
于 2019-12-10T22:35:59.537 回答