Reputation: 944
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.
Upvotes: 2
Views: 2225
Reputation: 944
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);
}
Upvotes: 1
Reputation: 174457
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
Upvotes: 1
Reputation: 2181
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?
Upvotes: 0
Reputation: 23214
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.
Upvotes: 0