我有这个剃刀模板
<table>
<tr>
<td>@Html.RadioButtonFor(i => i.Value, "1")</td>
<td>@Html.LabelFor(i => i.Value, "true")</td>
</tr>
<tr>
<td>@Html.RadioButtonFor(i => i.Value, "0")</td>
<td>@Html.LabelFor(i => i.Value, "false")</td>
</tr>
</table>
这给了我这个HTML
<table>
<tr>
<td><input id="Items_1__Value" name="Items[1].Value" type="radio" value="1" /></td>
<td><label for="Items_1__Value">true</label></td>
</tr>
<tr>
<td><input checked="checked" id="Items_1__Value" name="Items[1].Value" type="radio" value="0" /></td>
<td><label for="Items_1__Value">false</label></td>
</tr>
</table>
所以我有两次ID Items_1__Value
- 当然 - 不好,当我点击第二个标签“false”时,浏览器不能正常工作,第一个收音机将被激活。
我知道我可以在RadioButtonFor中添加一个自己的ID并用我的标签来引用它,但这不是很好,是吗?特别是因为我处于一个循环中而且不能只使用带有附加数字的名称“value”,这也会在我的最终HTML标记中以多个Dom Ids结束。
不应该是良好的解决方案吗?
答案 0 :(得分:57)
不要过度设计解决方案。你要做的就是让单选按钮响应文本的点击。保持简单,只需将单选按钮包裹在标签标签中:
<table>
<tr>
<td><label>@Html.RadioButtonFor(i => i.Value, "1")True</label></td>
</tr>
<tr>
<td><label>@Html.RadioButtonFor(i => i.Value, "0")False</label></td>
</tr>
</table>
LabelFor html帮助程序通常用于从View模型的Display属性中引入Name(例如“[Display(Name =”输入您的名字))]。
使用单选按钮时,名称并不是特别有用,因为每个单选按钮都有不同的文本行,这意味着您无论如何都难以将文本编码到视图中。
答案 1 :(得分:47)
我一直想知道MVC如何确定“嵌套”字段名称和ID。对MVC源代码进行了一些研究,但我觉得我有一个很好的解决方案。
随着EditorTemplates和DisplayTemplates的引入,MVC框架添加了ViewData.TemplateInfo
,其中包含当前“字段前缀”,例如"Items[1]."
。嵌套模板使用它来创建唯一的名称和ID。
TemplateInfo
类包含一个有趣的方法GetFullHtmlFieldId
。我们可以使用它来创建我们自己的唯一ID,如下所示:
@{string id = ViewData.TemplateInfo.GetFullHtmlFieldId("fieldName");}
@* This will result in something like "Items_1__fieldName" *@
以下是如何为您的示例实现正确的行为:
<table>
<tr>
@{string id = ViewData.TemplateInfo.GetFullHtmlFieldId("radioTrue");}
<td>@Html.RadioButtonFor(i => i.Value, "1", new{id})</td>
<td>@Html.LabelFor(i => i.Value, "true", new{@for=id})</td>
</tr>
<tr>
@{id = ViewData.TemplateInfo.GetFullHtmlFieldId("radioFalse");}
<td>@Html.RadioButtonFor(i => i.Value, "0", new{id})</td>
<td>@Html.LabelFor(i => i.Value, "false", new{@for=id})</td>
</tr>
</table>
这将为您提供以下HTML:
<table>
<tr>
<td><input id="Items_1__radioTrue" name="Items[1].Value" type="radio" value="1" /></td>
<td><label for="Items_1__radioTrue">true</label></td>
</tr>
<tr>
<td><input checked="checked" id="Items_1__radioFalse" name="Items[1].Value" type="radio" value="0" /></td>
<td><label for="Items_1__radioFalse">false</label></td>
</tr>
</table>
我的Razor语法不发达,所以如果此代码有语法错误,请告诉我。
非常不幸的是,RadioButtonFor
没有内置此功能。似乎合乎逻辑的是,所有渲染的单选按钮都应该具有一个ID name
和value
的组合,但事实并非如此 - 可能因为它与所有其他Html助手不同。登记/>
为此功能创建自己的扩展方法似乎也是一种合理的选择。但是,使用“表达式语法”可能会变得棘手...所以我建议重载.RadioButton(name, value, ...)
而不是RadioButtonFor(expression, ...)
。你可能也希望.Label(name, value)
过载
我希望这一切都有道理,因为该段落中有很多“填空”。
答案 2 :(得分:8)
@Html.LabelFor
没有重载需要3个参数。我发现使用普通@Html.Label
可以正常工作:
@{string id = ViewData.TemplateInfo.GetFullHtmlFieldId("radioButton_True");}
@Html.Label(id, "True:")
@Html.RadioButtonFor(m => m.radioButton, true, new { id })
@{id = ViewData.TemplateInfo.GetFullHtmlFieldId("radioButton_False");}
@Html.Label(id, "False:")
@Html.RadioButtonFor(m => m.radioButton, false, new { id })
这允许您单击标签并按照您的预期选择相关的单选按钮。
答案 3 :(得分:1)
不完美但是工作,
<table>
<tr>
<td>@ReplaceName(Html.RadioButtonFor(i => i.Value, "1"))</td>
<td>@Html.LabelFor(i => i.Value[0], "true")</td>
</tr>
<tr>
<td>@ReplaceName(Html.RadioButtonFor(i => i.Value, "0"))</td>
<td>@Html.LabelFor(i => i.Value[1], "false")</td>
</tr>
</table>
@functions {
int counter = 0;
MvcHtmlString ReplaceName(MvcHtmlString html){
return MvcHtmlString.Create(html.ToString().Replace("__Value", "__Value_" + counter++ +"_"));
}
}
答案 4 :(得分:0)
这是您可以使用的HtmlHelper,但您可以自定义它。只有勉强测试,所以YMMV。
public static MvcHtmlString RadioButtonWithLabelFor<TModel, TProperty>(this HtmlHelper<TModel> helper, Expression<Func<TModel, TProperty>> expression, object value, object htmlAttributes = null)
{
var name = ExpressionHelper.GetExpressionText(expression);
var id = helper.ViewData.TemplateInfo.GetFullHtmlFieldId(name + "_" + value);
var viewData = new ViewDataDictionary(helper.ViewData) {{"id", id}};
if (htmlAttributes != null)
{
var viewDataDictionary = HtmlHelper.AnonymousObjectToHtmlAttributes(htmlAttributes);
foreach (var keyValuePair in viewDataDictionary)
{
viewData[keyValuePair.Key] = keyValuePair.Value;
}
}
var radioButton = helper.RadioButtonFor(expression, value, viewData);
var tagBuilder = new TagBuilder("label");
tagBuilder.MergeAttribute("for", id);
tagBuilder.InnerHtml = value.ToString();
return new MvcHtmlString(radioButton.ToHtmlString() + tagBuilder.ToString());
}
答案 5 :(得分:0)
您可以添加带标签的文字
<td>@Html.RadioButtonFor(i => i.Value, true) <text>True</text></td>
<td>@Html.RadioButtonFor(i => i.Value, false) <text>False</text></td>
答案 6 :(得分:-2)
显然有一个很好的解决方案
<td>@Html.RadioButtonFor(i => i.Value, true)</td>
<td>@Html.RadioButtonFor(i => i.Value, false)</td>