使用 RadioButtonFor 编写一组单选按钮的正确方法

Correct Way to Code a Group of Radio Buttons using RadioButtonFor

根据我的研究,在 MVC 中编写复选框的正确方法如下。

@Html.CheckBoxFor(m => m.RememberMe)
@Html.LabelFor(m => m.RememberMe)

这将呈现一个复选框,为该复选框呈现一个标签,并使该标签 可点击,这意味着点击该标签也会切换该复选框。

但是对于单个视图模型字段有多个复选框的情况呢? (例如,也许每个复选框代表一个整数值中的一个位。)或者,更好的是,单选按钮呢,其中总是有多个选项与同一字段相关联?

在这些情况下,上面的代码似乎有问题。要么不是所有元素都与同一个字段相关联,要么会呈现具有 same ID 的多个元素。

我研究这个已经有一段时间了。我找到了很多解决方案;然而,它们似乎都没有可点击的标签,或者它们需要一堆自定义 and/or 非标准编码。有些人完全避免使用 RadioButtonFor/LabelFor,而是选择对原始 HTML.

进行编码

编码原始 HTML 很好,但是 MVC 的设计者难道没有预料到我们可能需要为同一字段使用多个单选按钮吗?而且,如果他们这样做了,他们打算如何对其进行编码?

编辑:

在进一步研究之后,下面的代码是我发现的对单选按钮进行编码的最佳方式。此代码假设我已经为我的每个无线电选项定义了一个枚举。

@Html.RadioButtonFor(m => m.Gender, Gender.Male, new { id = "gender-male" })
@Html.LabelFor(m => m.Gender, Gender.Male.ToString(), new { @for = "gender-male" })
@Html.RadioButtonFor(m => m.Gender, Gender.Female, new { id = "gender-female" })
@Html.LabelFor(m => m.Gender, Gender.Female.ToString(), new { @for = "gender-female" })

也许这是我所能期待的最好的结果,但它仍然让我有些困扰。

  1. 为什么需要对 ID 等基本内容进行如此多的自定义?同样,Microsoft 难道没有预料到我们会想要与同一字段相关联的多个单选按钮吗?

  2. 如果枚举名称与我想要的单选按钮标签的描述不同,这种方法似乎不支持字段属性,例如[Display(Name = "")]

(我想正确处理多个复选框将推迟到另一个问题。)

好的,让我们做一些研究。首先,您不需要唯一 ID 即可通过单击标签来切换 checkbox/radio。实际上你根本不需要 id !您所要做的就是将您的输入包装在 <label> 标签内:

<label>
    <input type="radio" name="radio" value="1" /> Radio 1   
</label>

到目前为止一切顺利,ASP.NET MVC 使您能够编写自己的 html 帮助程序,让我们为 Enum 模型字段编写一个!

想象一下,我们有一些注册模型:

public class RegisterViewModel
{
    [Required]
    [EmailAddress]
    [Display(Name = "Email")]
    public string Email { get; set; }

    [Required]
    [StringLength(100, ErrorMessage = "The {0} must be at least {2} characters long.", MinimumLength = 6)]
    [DataType(DataType.Password)]
    [Display(Name = "Password")]
    public string Password { get; set; }

    [DataType(DataType.Password)]
    [Display(Name = "Confirm password")]
    [Compare("Password", ErrorMessage = "The password and confirmation password do not match.")]
    public string ConfirmPassword { get; set; } 
}

妈的!我刚刚复制粘贴教程模型 o_O。我们现在想要的 - 是获取用户的性别,所以我们添加一个 Gender 枚举:

public enum Gender
{
    Iamparanoic = 0,

    Male = 1,

    Female = 2,
}

并将 Gender 类型的 Gender 字段添加到我们的模型中(希望 C# 有一个 Gender 访问修饰符!)

public Gender Gender { get; set; }

现在,是时候使用一些 asp.net 魔法并编写我们的 html 助手了:

public static MvcHtmlString RadioButtonsListForEnum<TModel, TEnum>(this HtmlHelper<TModel> htmlHelper, Expression<Func<TModel, TEnum>> expression)
{
    var sb = new StringBuilder();
    sb.Append("<ul>"); //we want it to look cool, dont' we?
    foreach (var value in Enum.GetValues(typeof(TEnum)))
    {
        var radio = htmlHelper.RadioButtonFor(expression, value).ToHtmlString(); //you can generage any id and pass it to helper, or use a tagbuilder

        sb.AppendFormat(
            "<li><label>{0} {1}</label></li>",
            radio,
            ((Enum)value).GetEnumName() //instead of it you can grab e.g. Display/Description attribute value or w/e else
        );
    }
    sb.Append("</ul");
    return MvcHtmlString.Create(sb.ToString());
}

它的用法如下:

@Html.RadioButtonsListForEnum(m => m.Gender)

很漂亮,不是吗?当然,您可以添加很多自定义项,例如使用独特的 mvc 样式 id 渲染单选按钮、各种 html 属性等。但这只是一个示例,踢到正确的方式。

接下来,我们还要渲染checkboxlist!

public static MvcHtmlString CheckBoxListForEnum<TModel, TEnum>(this HtmlHelper<TModel> htmlHelper, Expression<Func<TModel, TEnum>> expression, IDictionary<string, object> htmlAttributes = null)
{
    var metadata = ModelMetadata.FromLambdaExpression(expression, htmlHelper.ViewData);
    var enumValue = Convert.ToInt32(metadata.Model);

    var sb = new StringBuilder();
    foreach (var value in Enum.GetValues(typeof (TEnum)))
    {
        var val = Convert.ToInt32(value);
        var checkbox = new TagBuilder("input");

        checkbox.MergeAttribute("type", "checkbox");
        checkbox.MergeAttribute("value", value.ToString());
        checkbox.MergeAttribute("name", htmlHelper.NameFor(expression).ToString());

        if ((enumValue & val) == val)
            checkbox.MergeAttribute("checked", "checked");
        if (htmlAttributes != null)
            checkbox.MergeAttributes(htmlAttributes);

        var label = new TagBuilder("label") { InnerHtml = checkbox + ((Enum)value).GetEnumName() };

        sb.Append(label);
        sb.Append("<br/>");
    }
    return new MvcHtmlString(sb.ToString());
}

再一次,简单的用法:

@Html.CheckBoxListForEnum(m => m.Gender)

顺便说一句,它只对用 Flags 属性标记的枚举有意义,当然你会遇到模型绑定的问题——它需要自定义绑定器。但这是另一个问题,我希望 Jon Skeet 可以回答:)

在我看来,我认为微软方面无能为力来处理你所说的情况。

从Html代码开始,在html中如何呈现多单选按钮?

<form action="">
<input type="radio" name="sex" value="male">Male<br>
<input type="radio" name="sex" value="female">Female
</form>

上面是我从W3cSchools,

拿来的样本

如果您想通过单击标签来切换单选按钮,可以通过 html

中的两种方式完成

第一种方式是在标签中使用for标签

<input type="radio" id="myId" name="MyName" value="MyValue" />
<label for="myId">Display Name</label>

第二种方法是将收音机输入放在标签内

<label>
   <input type="radio" id="myId" name="MyName" value="MyValue"/> 
   Display Name
</label>

如您所见,当您单击标签时,它的标签组合会切换单选按钮,我认为 Microsoft 使开发人员可以简单灵活地选择要做什么以及以他喜欢的方式.

现在,要在 Mvc 中获得相同的结果,您可以使用上面提到的这两种方法之一对每个单选按钮进行硬编码,或者为了更简单,编写您自己的 Mvc Html 扩展,我推荐第二种方法。

希望对您有所帮助