'How to create custom HtmlHelper for nullable Boolean radio button group in .NET Core

Trying to make a custom MVC control

enter image description here

        [Display(Name = "Do you agree?")]
        [Required]
        public bool? Agree { get; set; }


Solution 1:[1]

I have the following solution that I came up with

using Microsoft.AspNetCore.Html;
using Microsoft.AspNetCore.Mvc.Rendering;
using Microsoft.AspNetCore.Mvc.ViewFeatures;
using System;
using System.Linq.Expressions;
using System.Text;

namespace MyNameSpace
{
    public static partial class HtmlHelpers
    {
        public static IHtmlContent RadioButtonsBooleanFor<TModel, TProperty>(this IHtmlHelper<TModel> html, Expression<Func<TModel, TProperty>> expression)
        {
            var expressionProvider = new ModelExpressionProvider(html.MetadataProvider);
            var metadata = expressionProvider.CreateModelExpression(html.ViewData, expression);

            var type = metadata.ModelExplorer.ModelType;
            if (!(type == typeof(bool) || type == typeof (bool?)))
                throw new InvalidCastException("Property must be either bool or bool?.");

            var value = (bool?)metadata.Model;
            var isYesChecked = value ?? false ? "checked=\"checked\"" : String.Empty;
            var isNoChecked = !(value ?? true) ? "checked=\"checked\"" : String.Empty;
            var validationMessage = $"The {metadata.Metadata.DisplayName} field is required.";

            var output = new StringBuilder();
            output.AppendLine("<div class=\"boolRadio\">");
            output.AppendLine($"<input data-val=\"true\" data-val-required=\"{validationMessage}\" id =\"{metadata.Name}_yes\" name=\"{metadata.Name}\" type=\"radio\" value=\"True\" {isYesChecked}/><span>Yes</span>");
            output.AppendLine($"<input id=\"{metadata.Name}_no\" name=\"{metadata.Name}\" type=\"radio\" value=\"False\" {isNoChecked}/><span>No</span>");
            output.AppendLine($"<label for=\"{metadata.Name}_yes\">{metadata.Metadata.DisplayName}</label>");
            output.AppendLine("</div>");
            output.AppendLine($"<span class=\"field-validation-valid text-danger \" data-valmsg-for=\"{metadata.Name}\" data-valmsg-replace=\"true\"></span>");

            return new HtmlString(output.ToString());
        }
    }
}

css:

.boolRadio{
    height: 20px;
}
.boolRadio > span{
    margin: 0 10px 0 5px;
}

To use with model property Agree

@Html.RadioButtonsBooleanFor(m=>m.Agree)

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 Murometz80