In ASP.NET MVC, a ViewModel can be easily defined as a container-type class which represents only the data we want to display on our web page. In any standard MVC-based ASP.NET application, the ViewModel is instantiated by the Controller in response to a GET request using the data fetched from the model. Once built, the ViewModel is passed to the View, where it's used to populate the page contents/input fields with their property values: this "binding" happens thanks to the Html.*For helper methods available in Razor, such as:
- Html.LabelFor
- Html.TextBoxFor
- Html.CheckBoxFor
- Html.EditorFor
- Html.DropDownListFor
...And so on.
Each one of them gets and sets the ViewModel property given to it in the first parameter, which can be done in the following way:
1 2 3 4 5 6 7 8 |
@model SomeModel; <!-- ...some HTML... --> @Html.LabelFor(m => m.SomeModelProperty) @Html.TextBoxFor(m => m.SomeModelProperty) <!-- ...more HTML... --> |
When the properties are of text and/or numeric types - string, int, double, float and so on - the process it's pretty much straightforward, expecially if they end up into text boxes using the Html.TextBoxFor() or Html.EditoFor() methods: it's not that easy when we need to translate a nullable boolean type property ( bool? ) into a DropDownListFor or a CheckBoxFor : how to ensure that the values will be properly translated between the ViewModel and the HTML?
For a DropDownListFor , here's how we can do that:
DropDownListFor with Boolean:
1 2 3 4 5 6 7 8 9 10 11 12 |
@model SomeModel <!-- ...some HTML... --> @Html.DropDownListFor(m => m.BooleanProperty, new SelectList( new[] { new { Value = "true", Text = "YES" }, new { Value = "false", Text = "NO" }, }, "Value", "Text" )) |
DropDownListFor with Nullable Boolean:
1 2 3 4 5 6 7 8 9 10 11 12 13 |
@model SomeModel <!-- ...some HTML... --> @Html.DropDownListFor(m => m.NullableBooleanProperty, new SelectList( new[] { new { Value = "", Text = "-- Choose YES or NO --" }, new { Value = "true", Text = "YES" }, new { Value = "false", Text = "NO" }, }, "Value", "Text" )) |
In the ViewModel:
1 2 3 4 5 6 7 8 9 10 11 |
public bool NullableBooleanPropertyProxy { get { return NullableBooleanProperty == true; } set { NullableBooleanProperty = value; } } |
In the View:
1 2 3 4 5 |
@model SomeModel <!-- ...some HTML... --> @Html.CheckBoxFor(m => m.NullableBooleanPropertyProxy) |
All the above suggestions and workarounds are fully working in MVC 4, MVC5, MVC6 and ASP.NET Core MVC.
Many thanks to this great article written by Brad Wilson for the insights that led me to write this post!