Simple question really.
I have MVC view that displays a Nullable Bool, e,g,
Html.CheckBoxFor(model=>model.NullableBoolHere, Model.NullableBoolHere,
and I want to create a new html helper, that will accept this type, and then convert
Null || False => False
True => True
so I have the following
public static MvcHtmlString CheckBoxFor<TModel>(this HtmlHelper<TModel> htmlHelper, Expression<Func<TModel, bool?>> expression, object htmlAttributes, bool disabled)
{
IDictionary<string, object> values = new RouteValueDictionary(htmlAttributes);
if (disabled)
values.Add("disabled", "true");
Expression<Func<TModel, bool>> boolExpression = CONVERT_TO_BOOL_HERE(expression);
return htmlHelper.CheckBoxFor(expression, values);
}
Any help appreciated, I understand I will have to use recursion to copy the expression, but just not sure how to go about navigating the expression itself, find the bool?, convert to bool.
You can use this code:
var body = Expression.Coalesce(expression.Body, Expression.Constant(false));
var boolExpression = (Expression<Func<TModel, bool>>)
Expression.Lambda(body, expression.Parameters.First());
The advantage to the other answers is that it doesn't compile the first expression, it just wraps it. The resulting expression is similar to one created by this code:
m => m.NullableBoolHere ?? false
Check it live.
So, in the end, the only way I could find to do it was to resolve the bool? into a bool myself, then return a 'normal' checkbox by passing in the correct name etc.
This does work a treat though, so all good. If you do know a better way of getting the correct ParameterName, it would be great to hear.
public static MvcHtmlString CheckBoxFor<TModel>(this HtmlHelper<TModel> htmlHelper, Expression<Func<TModel, bool?>> expression, object htmlAttributes, bool disabled)
{
IDictionary<string, object> values = new RouteValueDictionary(htmlAttributes);
if (disabled)
values.Add("disabled", "true");
//Compile the expression to get the value from it.
var compiled = expression.Compile().Invoke(htmlHelper.ViewData.Model);
bool checkValue = compiled.HasValue ? compiled.Value : false; //evaluate the compiled expression
//Get the name of the id we should use
//var parameterName = ((MemberExpression)expression.Body).Member.Name; // only gives the last part
string parameterName = expression.Body.ToString().Replace("model.", "");//.Replace(".", HtmlHelper.IdAttributeDotReplacement);
//Return our 'hand made' checkbox
return htmlHelper.CheckBox(parameterName, checkValue, values);
}
I guess it won't be enough to just convert the expression to another type, MVC uses expressions for a reason so I suspect it needs to examine the given expression and apply some magic on it.
You can create a new expression that does the conversion, like this:
Expression<Func<TModel, bool>> boolExpression =
T => expression.Compile()(T).GetValueOrDefault(false);
But as I said, I suspect it will not be enough, MVC probably wants to examine model members etc inside the expression.
How about this:
Expression<Func<TModel, bool>> boolExpression = model =>
{
bool? result = expression.Compile()(model);
return result.HasValue ? result.Value : false;
};
That way you wrap the original expression and you can convert the result from bool? to bool.
Does it solve your problem?