使用 RadioButtonFor 编码一组单选按钮的正确方法 [英] Correct Way to Code a Group of Radio Buttons using RadioButtonFor

查看:22
本文介绍了使用 RadioButtonFor 编码一组单选按钮的正确方法的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

Based on my research, the correct way to code a checkbox in MVC is as follows.

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

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

This will render a checkbox, render a label for the checkbox, and make the label clickable, which means clicking the label also toggles the checkbox.

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

But what about the case where there are multiple checkboxes for a single view-model field? (For example, maybe each checkbox represents a bit within an integer value.) Or, better yet, what about radio buttons, where there are always several options associated with the same field?

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

In these cases, there seems to be issues with the code above. Either not all elements would be associated with the same field, or multiple elements with the same ID would be rendered.

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

I have been researching this for a while now. I have found many solutions; however, they all seem to either not have a clickable label, or they require a bunch of custom and/or non-standard coding. Some avoid the use of RadioButtonFor/LabelFor completely, choosing instead to code the raw HTML.

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

Coding the raw HTML is fine, but didn't the designers of MVC not anticipate that we may need multiple radio buttons for the same field? And, if they did, how did they intended it to be coded?

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

After researching this some more, the code below is the best way I've found to code radio buttons. This code assumes I've defined an enum for each of my radio options.

@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" })

也许这是我能预料到的最好的,但它仍然让我有点困扰.

Maybe this is the best I can expect, but it still troubles me a little.

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

  1. Why is so much customization for basic stuff such as IDs required? Again, didn't Microsoft anticipate that we'd want multiple radio buttons associated with the same field?

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

if the enum name isn't the same as the description I want for the radio button label, this approach doesn't seem to support field attributes such as [Display(Name = "")].

(我猜对多个复选框的正确处理将推迟到另一个问题.)

(I guess the correct handling of multiple checkboxes will be deferred to another question.)

推荐答案

好的,让我们做一些研究.首先,您不需要唯一的 id 来通过单击标签来切换复选框/收音机.实际上你根本不需要 id !您所要做的就是将您的输入包装在 <label> 标签中:

Ok, let's do some research. First of all, you don't need unique id to toggle checkbox/radio by clicking a label. Actually you don't need id at all! All you have to do is wrap your input inside <label> tag:

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

到目前为止一切顺利,ASP.NET MVC 为您提供了编写自己的 html 助手的能力,让我们为 Enum 模型字段编写一个!

So far so good, ASP.NET MVC provides you ability to code your own html helpers, let's write one for Enum model field!

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

Imagine, we've got some registration model:

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 枚举:

Damn! I've just copy-pasted tutorial model o_O. What we want now - is to get user's gender, so we add a Gender enum:

public enum Gender
{
    Iamparanoic = 0,

    Male = 1,

    Female = 2,
}

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

and add Gender field of Gender type to our model (wish, c# had a Gender access modifier!)

public Gender Gender { get; set; }

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

Now, time to use some asp.net magic and write our html helper:

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 属性等,但这只是一个示例,正确的方式.

So pretty, isn't it? Of course you can add hella lot's of customization, like rendering radiobuttons with unique mvc-style id's, all kindes of html attributes etc. but this is just a sample, ass kick to right way.

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

Next, we also want to render 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 可以回答:)

Btw, it makes sence just for enums marked with Flags attribute, and of course you'll have troubles with model binding - it requires custom binder. But it's another question, and i hope Jon Skeet can answer it :)

这篇关于使用 RadioButtonFor 编码一组单选按钮的正确方法的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆