RichC
RichC

Reputation: 7879

Creating a radiobutton list for Enums that can be nullable

I have the following code that successfully converts an Enum into a radiobutton list. However, it doesn't work if the Enum is nullable. Is it possible to allow for nullable enums?

public static MvcHtmlString EnumRadioButtonListFor<TModel, TProperty>(this HtmlHelper<TModel> htmlHelper, Expression<Func<TModel, TProperty>> expression)
    {
        var metaData = ModelMetadata.FromLambdaExpression(expression, htmlHelper.ViewData);

        var listOfValues = Enum.GetNames(metaData.ModelType);  //<--- It errors here if the enum is nullable

        var sb = new StringBuilder();

        if (listOfValues != null)
        {             
            sb = sb.AppendFormat(@"<span class=""radio"">");

            // Create a radio button for each item in the list
            foreach (var name in listOfValues)
            {
                var label = name;

                var memInfo = metaData.ModelType.GetMember(name);

                if (memInfo != null)
                {
                    var attributes = memInfo[0].GetCustomAttributes(typeof(DisplayAttribute), false);

                    if (attributes != null && attributes.Length > 0)
                        label = ((DisplayAttribute)attributes[0]).Name;
                }

                var id = string.Format(
                    "{0}_{1}_{2}",
                    htmlHelper.ViewData.TemplateInfo.HtmlFieldPrefix,
                    metaData.PropertyName,
                    name
                );

                int enumValue = (int)Enum.Parse(metaData.ModelType, name);

                var radio = htmlHelper.RadioButtonFor(expression, enumValue, new { id = id }).ToHtmlString();

                sb.AppendFormat(@"<label for=""{0}"">{1}{2}</label><br />", id, radio, label);
            }

            sb = sb.AppendFormat("</span>");
        }

        return MvcHtmlString.Create(sb.ToString());
    }

The error I get on the line noted in the code is this:

Type provided must be an Enum. Parameter name: enumType

This is how I'm implementing it using MVC:

Class:

    public enum IdTypes
    {
        [Display(Name="Driver's License")]
        DriversLicense = 1,
        [Display(Name="State ID")]
        StateID = 2,
        [Display(Name="US Passport")]
        UsPassport = 3,
        [Display(Name="Green Card")]
        GreenCard = 4
    }

    [Display(Name="Photo ID Provided")]
    [UIHint("EnumRadioButtonListFor")]
    public IdTypes? PhotoIDProvidedSecondary { get; set; }

Razor:

    <div class="form-group">
        @Html.LabelFor(model => model.PhotoIDProvidedSecondary, htmlAttributes: new { @class = "control-label col-md-3" })
        <div class="col-md-2">
            @Html.EditorFor(model => model.PhotoIDProvidedSecondary, new { htmlAttributes = new { @class = "form-control" } })
        </div>
        <div class="col-md-4">
            <p class="form-control-static">@Html.ValidationMessageFor(model => model.PhotoIDProvidedSecondary, "", new { @class = "text-danger" })</p>
        </div>
    </div>

EditorTemplate (EnumRadioButtonListFor):

@model Enum
@using BrokerDealer.Extensions

@if (EnumHelper.IsValidForEnumHelper(ViewData.ModelMetadata))
{
    @Html.EnumRadioButtonListFor(model => model)
}
else
{
    @Html.TextBoxFor(model => model, htmlAttributes: new { @class = "form-control" })
}

Upvotes: 1

Views: 588

Answers (1)

Jeff S
Jeff S

Reputation: 7484

I can't test it at the moment, but if you change the line failing to be:

var myEnum = Nullable.GetUnderlyingType(metaData.ModelType) ?? metaData.ModelType;
var listOfValues = Enum.GetNames(myEnum);

You should get the result you are expecting.

Upvotes: 2

Related Questions