我的模型包含一个枚举,我试图绑定到一个单选按钮列表,这样在提交表单时只能选择一个值。
public enum Options
{
[Display(Name="Option A")
OptionA,
[Display(Name="Option B")
OptionB
}
public class MyModel
{
public Options SelectedOption {get; set;}
public string TextA{get; set;}
public string TextB{get; set;}
}
在MVC 5中,我会为每个枚举值渲染一个单选按钮输入,用户只能选择一个。因此,每个单选按钮的视图中的代码可能如下所示:
@Html.RadioButtonFor(m => m.SelectedOption, Options.OptionA)
MVC6的问题似乎是输入标记帮助程序不支持开箱即用的枚举属性。因此,如果我尝试添加<input asp-for="SelectedOption"/>
,我得到的只是一个文本框。
所以我的问题是,有没有办法使用MVC6标签助手(开箱即用或自定义)或者还有另一种方法吗?也许类似于使用旧的剃刀语法或只是添加输入标签并填充其属性?
请注意,理想情况下,两个单选按钮都必须有标签,以显示枚举[Display]
属性中指定的文字。此外,TextA
或TextB
文本框中只有一个可以同时出现,这应该基于所选的单选按钮,但这超出了问题的范围。所以这里是渲染标记的样子(或多或少):
<div>
<div>
<input id="OptionA" type="radio" name="SelectedOption"/>
<label for="OptionA">Option A</label>
</div>
<div>
<label for="TextA">Text A</label>
<input type="text" id="TextA" name="TextA">
</div>
<div>
<div>
<div>
<input id="OptionB" type="radio" name="SelectedOption"/>
<label for="OptionB">Option B</label>
</div>
<div>
<label for="TextB">Text A</label>
<input type="text" id="TextB" name="TextB">
</div>
<div>
答案 0 :(得分:1)
<enum-radio-button asp-for="ThisEnum"></enum-radio-button>
<enum-radio-button asp-for="ThisEnum" value="ThisEnum.Value001"></enum-radio-button>
ThisEnum.Value001 =自动检查无线电输入..
用于枚举单选按钮列表的Asp.Net Core TagHelper
/// <summary>
/// <see cref="ITagHelper"/> implementation targeting <enum-radio-button> elements with an <c>asp-for</c> attribute, <c>value</c> attribute.
/// </summary>
[HtmlTargetElement("enum-radio-button", Attributes = RadioButtonEnumForAttributeName)]
public class RadioButtonEnumTagHelper : TagHelper
{
private const string RadioButtonEnumForAttributeName = "asp-for";
private const string RadioButtonEnumValueAttributeName = "value";
/// <summary>
/// Creates a new <see cref="RadioButtonEnumTagHelper"/>.
/// </summary>
/// <param name="generator">The <see cref="IHtmlGenerator"/>.</param>
public RadioButtonEnumTagHelper(IHtmlGenerator generator)
{
Generator = generator;
}
/// <inheritdoc />
public override int Order => -1000;
[HtmlAttributeNotBound]
[ViewContext]
public ViewContext ViewContext { get; set; }
protected IHtmlGenerator Generator { get; }
/// <summary>
/// An expression to be evaluated against the current model.
/// </summary>
[HtmlAttributeName(RadioButtonEnumForAttributeName)]
public ModelExpression For { get; set; }
[HtmlAttributeName(RadioButtonEnumValueAttributeName)]
public Enum value { get; set; }
/// <inheritdoc />
/// <remarks>Does nothing if <see cref="For"/> is <c>null</c>.</remarks>
public override async Task ProcessAsync(TagHelperContext context, TagHelperOutput output)
{
var childContent = await output.GetChildContentAsync();
string innerContent = childContent.GetContent();
output.Content.AppendHtml(innerContent);
output.TagName = "div";
output.TagMode = TagMode.StartTagAndEndTag;
output.Attributes.Add("class", "btn-group btn-group-radio");
if (context == null)
{
throw new ArgumentNullException(nameof(context));
}
if (output == null)
{
throw new ArgumentNullException(nameof(output));
}
var modelExplorer = For.ModelExplorer;
var metaData = For.Metadata;
if (metaData.EnumNamesAndValues != null)
{
foreach (var item in metaData.EnumNamesAndValues)
{
string enum_id = $"{metaData.ContainerType.Name}_{metaData.PropertyName}_{item.Key}";
bool enum_ischecked = false;
if (value != null)
{
if (value != null && item.Key.ToString() == value.ToString())
{
enum_ischecked = true;
}
}
else
{
if (For.Model != null && item.Key.ToString() == For.Model.ToString())
{
enum_ischecked = true;
}
}
string enum_input_label_name = item.Key;
var enum_resourced_name = metaData.EnumGroupedDisplayNamesAndValues.Where(x => x.Value == item.Value).FirstOrDefault();
if (enum_resourced_name.Value != null)
{
enum_input_label_name = enum_resourced_name.Key.Name;
}
var enum_radio = Generator.GenerateRadioButton(
ViewContext,
For.ModelExplorer,
metaData.PropertyName,
item.Key,
false,
htmlAttributes: new { @id = enum_id });
enum_radio.Attributes.Remove("checked");
if (enum_ischecked)
{
enum_radio.MergeAttribute("checked", "checked");
}
output.Content.AppendHtml(enum_radio);
var enum_label = Generator.GenerateLabel(
ViewContext,
For.ModelExplorer,
For.Name,
enum_input_label_name,
htmlAttributes: new { @for = enum_id, @Class = "btn btn-default" });
output.Content.AppendHtml(enum_label);
}
}
}
}
我使用这种风格
答案 1 :(得分:0)
在netcore mvc 6中实现静态的一种方法
public static IHtmlContent RadioButtonSwitchEnumFor<TModel, TProperty>(this IHtmlHelper<TModel> htmlHelper, Expression<Func<TModel, TProperty>> expression, object selectedValue = null, bool? isHorizontal = true, object htmlAttributes = null)
{
if (htmlHelper == null) throw new ArgumentNullException(nameof(htmlHelper));
if (expression == null) throw new ArgumentNullException(nameof(expression));
var viewData = htmlHelper.ViewData;
var modelExpressionProvider = (ModelExpressionProvider)htmlHelper.ViewContext.HttpContext.RequestServices.GetService(typeof(IModelExpressionProvider));
var modelExplorer = modelExpressionProvider.CreateModelExpression(viewData, expression);
if (modelExplorer == null) throw new InvalidOperationException($"Failed to get model explorer for {modelExplorer}");
var metaData = modelExplorer.Metadata;
if (!metaData.ModelType.IsEnum)
{
throw new ArgumentException("This helper is intended to be used with enum types");
}
// get the field name
var propertyName = metaData.PropertyName ?? viewData?.ModelMetadata?.Name;
string ctrlName = propertyName?.Replace(".", "");
var names = Enum.GetNames(metaData.ModelType);
var values = Enum.GetValues(metaData.ModelType);
var sb = new StringBuilder();
// Create a radio button for each item in the list
foreach (var name in names)
{
string description = string.Empty;
var propertyValue = names.Where(e => e.StartsWith(name)).Select(e => (int)Enum.Parse(metaData.ModelType, e)).FirstOrDefault();
var memInfo = metaData.ModelType.GetMember(name);
var attributes = memInfo[0].GetCustomAttributes(typeof(DisplayAttribute), false);
if (attributes.Length > 0)
{
description = ((DisplayAttribute)attributes[0]).ResourceType != null ? ((DisplayAttribute)attributes[0]).GetName() : name;
}
// Create tag builder
var radio = new TagBuilder("input");
radio.Attributes.Add("id", $"{propertyName}_{name}");
radio.Attributes.Add("name", ctrlName);
radio.Attributes.Add("type", "radio");
radio.Attributes.Add("value", propertyValue.ToString());
string selectedFlag;
if (selectedValue != null)
{
if (propertyValue == Convert.ToInt32(selectedValue))
{
selectedFlag = "class='btn btn-sm btn-success active'";
radio.Attributes.Add("checked", "checked");
}
else
{
selectedFlag = "class='btn btn-sm btn-default'";
}
}
else
{
var selectedPropertyName = modelExplorer.Model;
if (selectedPropertyName != null)
{
if (name == selectedPropertyName.ToString())
{
selectedFlag = "class='btn btn-sm btn-success active'";
radio.Attributes.Add("checked", "checked");
}
else
{
selectedFlag = "class='btn btn-sm btn-default'";
}
}
else
{
if (names.First() == name)
{
selectedFlag = "class='btn btn-sm btn-success active'";
radio.Attributes.Add("checked", "checked");
}
else
{
selectedFlag = "class='btn btn-sm btn-default'";
}
}
}
// Add attributes
radio.MergeAttributes(new RouteValueDictionary(htmlAttributes));
using (var writer = new StringWriter())
{
radio.WriteTo(writer, HtmlEncoder.Default);
sb.AppendFormat("<label {0}>{1}{2}</label>", selectedFlag, writer.ToString(), HttpUtility.HtmlEncode(description));
}
}
var htmlContent = sb.ToString();
var wrapperBuilder = new TagBuilder("div");
wrapperBuilder.MergeAttribute("class", "btn-group btn-toggle radioList");
wrapperBuilder.MergeAttribute("data-toggle", "buttons");
wrapperBuilder.InnerHtml.AppendHtml(htmlContent);
using (var sw = new StringWriter())
{
wrapperBuilder.WriteTo(sw, HtmlEncoder.Default);
return new HtmlString(sw.ToString());
}
}