ASP.NET MVC 2 - Html.EditorFor a nullable type?
Asked Answered
M

5

12

I have two editor templates: one for decimal, and one for decimal? (nullable)

But when I have a nullable decimal in my model, it tries to load the normal decimal editor:

<%: Html.EditorFor(model => model.SomeDecimal )%>
<%: Html.EditorFor(model => model.SomeNullableDecimal )%>

The first one works fine, and loads the decimal editor template. The second one also tries to load the decimal template (and fails because it is not a decimal field).

The error message is:

The model item passed into the dictionary is null, but this dictionary requires 
a non-null model item of type 'System.Decimal'. 

My templates are declared like this:

Decimal template:

<%@ Control Language="C#" 
Inherits="System.Web.Mvc.ViewUserControl<System.Decimal>" %>

Nullable Decimal template:

<%@ Control Language="C#" 
Inherits="System.Web.Mvc.ViewUserControl<System.Decimal?>" %>

I know that I can make it work by passing in the template name, eg

But I would really prefer it to just work automatically by using the type just like all the other templates.

<%: Html.EditorFor(model => model.SomeNullableDecimal, 
"NullableDecimalTemplate" )%>
Macymad answered 24/7, 2010 at 3:54 Comment(6)
Are the names of your templates Decimal.ascx and Decimal?.ascx ?Bughouse
No they are Decimal.ascx and NullableDecimal.ascxMacymad
No one?.. Turns out I can "fix" it by copying the NullableDecimal.ascx code inside of Decimal.ascx. Strangely enough, a standard decimal can be used in the nullable template. I don't know why a non nullable decimal will work in a template that has code like: if (myDecimal.HasValue)Macymad
Same problem here with TimeSpan - I'm going with your "fix" - many thanks.Melanochroi
It's almost as if Decimal extends Decimal? but we know it doesn't Why does the NullableDecimal code work for the Decimal template? There no way to have a special template for a nullable type?Corunna
Well a Decimal can be cast to a nullable Decimal because it always has a value (and so an implicit cast exists), but you can't go the other way because there's no correct cast if the Nullable is null.Ferino
M
16

Thanks to Bryan for adding a bounty to try to get a positive solution, but I'm going to have to answer and say that I have found that the answer is definitely NO - you cannot have a nullable template auto-discovered from its type. You must use a template name.

This is the relevant quote from Brad Wilson's blog at http://bradwilson.typepad.com/blog/2009/10/aspnet-mvc-2-templates-part-3-default-templates.html. He is an authoritative source on MVC so I have to believe him when he says:

When searching for the type name, the simple name is used (i.e., Type.Name) without namespace. Also, if the type is Nullable, we search for T (so you’ll get the Boolean template whether you’re using “bool” or “Nullable”)

He also goes on to say

This means if you’re writing templates for value types, you will need to account for whether the value is nullable or not. You can use the IsNullableValueType property of ModelMetadata to determine if the value is nullable. We’ll see an example of this below with the built-in Boolean template.

So YES there is an answer to this question, but unfortunately the answer is NO.

To use a nullable template you must explictly use the template name:

<%: Html.EditorFor(model => model.SomeNullableDecimal, "NullableDecimalTemplate" )%>

Or you can use one template that handle both the nullable and the non nullable type:

<% if (ViewData.ModelMetadata.IsNullableValueType) { %>
    <%= Html.DropDownList("", TriStateValues, new { @class = "list-box tri-state" })%>
<% } else { %>
    <%= Html.CheckBox("", Value ?? false, new { @class = "check-box" })%>
<% } %>
Macymad answered 15/3, 2011 at 10:22 Comment(0)
L
2

In order to create a template for a nullable type, you name your template as the base value type and then create your editor template with a nullable model.

For example, I want to do a template for int?. I created an editor template named "int32.cshtml" and I'm using int? as the model.

Lianaliane answered 29/7, 2014 at 20:12 Comment(0)
G
1

The template would have to be named "Nullable`1". Since this would match any Nullable struct, you could do a switch on the model type and render the appropriate partial template based on the type from within the "Nullable`1.ascx"

Guardi answered 10/3, 2011 at 18:52 Comment(1)
My UK keyboard layout has failed me :PGrodno
M
0

There is no way to do it in the way you want. There can be only one template for Decimal and Decimal?. But you can determine in the template if the value passed in is of nullable type like this:

<% if (ViewData.ModelMetadata.IsNullableValueType) { %>
    <%= Html.DropDownList("", TriStateValues, new { @class = "list-box tri-state" })%>
<% } else { %>
    <%= Html.CheckBox("", Value ?? false, new { @class = "check-box" })%>
<% } %>

For more details check this blog post

Mayolamayon answered 14/2, 2011 at 18:49 Comment(0)
A
0

Yes, you can do this without specifying the template in Html.EditorFor, but then you need specify the template against nullable property using the UIhint attribute.

[UIHint("NullableDecimalTemplate")]
public decimal? SomeNullableDecimal { get; set; }
Amphiprostyle answered 11/1, 2017 at 6:9 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.