Complicating a primitive with hidden fields to clarify whether False or Null is not recommended.
Checkbox isn't what you should be using -- it really only has one state: Checked. Otherwise, it could be anything.
When your database field is a nullable boolean (bool?
), the UX should use 3-Radio Buttons, where the first button represents your "Checked", the second button represents "Not Checked" and the third button represents your null, whatever the semantics of null means. You could use a <select><option>
drop down list to save real estate, but the user has to click twice and the choices aren't nearly as instantaneously clear.
1 0 null
True False Not Set
Yes No Undecided
Male Female Unknown
On Off Not Detected
The RadioButtonList, defined as an extension named RadioButtonForSelectList, builds the radio buttons for you, including the selected/checked value, and sets the <div class="RBxxxx">
so you can use css to make your radio buttons go horizontal (display: inline-block), vertical, or in a table fashion (display: inline-block; width:100px;)
In the model (I'm using string, string for the dictionary definition as a pedagogical example. You can use bool?, string)
public IEnumerable<SelectListItem> Sexsli { get; set; }
SexDict = new Dictionary<string, string>()
{
{ "M", "Male"},
{ "F", "Female" },
{ "U", "Undecided" },
};
//Convert the Dictionary Type into a SelectListItem Type
Sexsli = SexDict.Select(k =>
new SelectListItem
{
Selected = (k.Key == "U"),
Text = k.Value,
Value = k.Key.ToString()
});
<fieldset id="Gender">
<legend id="GenderLegend" title="Gender - Sex">I am a</legend>
@Html.RadioButtonForSelectList(m => m.Sexsli, Model.Sexsli, "Sex")
@Html.ValidationMessageFor(m => m.Sexsli)
</fieldset>
public static class HtmlExtensions
{
public static MvcHtmlString RadioButtonForSelectList<TModel, TProperty>(
this HtmlHelper<TModel> htmlHelper,
Expression<Func<TModel, TProperty>> expression,
IEnumerable<SelectListItem> listOfValues,
String rbClassName = "Horizontal")
{
var metaData = ModelMetadata.FromLambdaExpression(expression, htmlHelper.ViewData);
var sb = new StringBuilder();
if (listOfValues != null)
{
// Create a radio button for each item in the list
foreach (SelectListItem item in listOfValues)
{
// Generate an id to be given to the radio button field
var id = string.Format("{0}_{1}", metaData.PropertyName, item.Value);
// Create and populate a radio button using the existing html helpers
var label = htmlHelper.Label(id, HttpUtility.HtmlEncode(item.Text));
var radio = String.Empty;
if (item.Selected == true)
{
radio = htmlHelper.RadioButtonFor(expression, item.Value, new { id = id, @checked = "checked" }).ToHtmlString();
}
else
{
radio = htmlHelper.RadioButtonFor(expression, item.Value, new { id = id }).ToHtmlString();
}// Create the html string to return to client browser
// e.g. <input data-val="true" data-val-required="You must select an option" id="RB_1" name="RB" type="radio" value="1" /><label for="RB_1">Choice 1</label>
sb.AppendFormat("<div class=\"RB{2}\">{0}{1}</div>", radio, label, rbClassName);
}
}
return MvcHtmlString.Create(sb.ToString());
}
}