EditorFor on nullable DateTime - “Nullable对象必须有值”。

时间:2011-12-20 19:20:52

标签: asp.net-mvc-3

我正在尝试显示一个允许用户为某人输入新作业的表单。我正在使用DateTime.cshtml EditorTemplate来处理赋值的DateTime值。不可为空的DateTime工作正常。可空的DateTime导致“InvalidOperationException:Nullable对象必须具有值”。

我有一个简单的viewmodel,如下所示:

AssignmentViewModel.cs:

public Person Person { get; set; }
public Assignment NewAssignment { get; set; }

Assignment.cs包含:

public DateTime AssignmentStartDate { get; set; }
public DateTime? AssignmentEndDate { get; set; }

我的AssignmentController Create()方法如下所示:

public ViewResult Create(int personId)
{
    Person person = personRepository.GetPersonById(personId);
    var newAssignment = new AssignmentViewModel { Person = person, NewAssignment = new Assignment() };
    return View(newAssignment);
}

我的Create.cshtml视图如下所示:

@model AssignmentViewModel

@using (Html.BeginForm("Create", "Assignment"))
{
    @Html.Hidden("NewAssignment.PersonId", Model.Person.PersonId)
    @Html.LabelFor(x => x.NewAssignment.AssignmentStartDate):
    @Html.EditorFor(x => x.NewAssignment.AssignmentStartDate.Date, new { cssClass = "datePicker" })
    <br />
    @Html.LabelFor(x => x.NewAssignment.AssignmentEndDate):
    @Html.EditorFor(x => x.NewAssignment.AssignmentEndDate.Value.Date, new { cssClass = "datePicker" })
    <br />
    <input type="submit" value="Send />
}

My DateTime.cshtml EditorTemplate看起来像:

@model DateTime?

@{
    String modelValue = "";
    if (Model.HasValue)
    {
        if (Model.Value != DateTime.MinValue)
        {
            modelValue = Model.Value.ToShortDateString();
        }
    }
}

@Html.TextBox("", modelValue, new { @class = "datePicker" })

当我尝试加载Create视图时,我在“@ Html.EditorFor(x =&gt; x.NewAssignment.AssignmentEndDate.Value)”行中得到了上述异常。

您可能想知道我为什么要传递AssignmentEndDate.Value.Date而不是仅传递AssignmentEndDate;原因是因为我试图达到将DateTime拆分为Date和TimeOfDay字段并将其与DateTimeModelBinder重新组合的程度。我正在使用与shown herehere类似的技术。

我可以通过更改我的控制器Create()方法来绕过错误,将AssignmentEndDate设置为DateTime.MinValue来实例化ViewModel,但对于可以为空的DateTime来说这似乎完全错误:

var newAssignment = new AssignmentViewModel 
                        { 
                            Person = person, 
                            NewAssignment = new Assignment { AssignmentEndDate = DateTime.MinValue } 
                        };

在通过为可空的DateTime提供值“绕过”错误之后发生了一些奇怪的事情;不需要的可空DateTime属性(AssignmentEndDate.Date)无法通过客户端验证。尝试提交表单会以红色突出显示该字段。

我该如何正确处理?

3 个答案:

答案 0 :(得分:5)

问题是您尝试检索AssignmentEndDate.Value.Date,但AssignmentEndDatenull,这会导致此错误。

由于您的编辑器模板接受DateTime?,因此您应该传递AssignmentEndDate。换句话说,从视图中删除.Value.Date

@Html.EditorFor(x => x.NewAssignment.AssignmentEndDate, new { cssClass = "datePicker" })

由于您的编辑器模板使用ToShortDateString(),因此无需&#34;截断&#34;从该日期开始的时间。

更新

关于你想要分开&#34;日期&#34;和&#34;时间&#34;编辑:

你可以这两种方式做到这一点。

1 - 您当前的DateTime?编辑器会为Model.Value.Date呈现一个字段,因此您只需将其扩展为同时为Model.Value.TimeOfDay呈现字段即可。例如:

@{
  DateTime? modelDate = (Model == null) ? (DateTime?)null : Model.Value.Date;
  TimeSpan? modelTime = (Model == null) ? (TimeSpan?)null : Model.Value.TimeOfDay;
}
@Html.TextBox(..., modelDate, new{@class="datePicker"})
@Html.TextBox(..., modelTime, new{@class="timePicker"})

2 - 您可以将上述功能拆分为2个独立的编辑器,&#34; DateOnly&#34;和#34; TimeOnly&#34;。然后,更新您的视图以调用两个编辑器:

@Html.EditorFor(x => x.NewAssignment.AssignmentEndDate, "DateOnly")
@Html.EditorFor(x => x.NewAssignment.AssignmentEndDate, "TimeOnly")

选择取决于您,是否要将日期和时间部分分开或分开,但这就是我解决此问题的方法。

答案 1 :(得分:2)

在Shared / DisplayTemplate文件夹中创建DateTime.cshtml

@model Nullable<DateTime>
@(Model != null ? string.Format(ViewData.ModelMetadata.DisplayFormatString ?? "{0:d}", Model) : string.Empty)

这支持在找到时使用的数据注释中的元数据。

答案 2 :(得分:0)

UPDATE:GetValueOrDefault将其视为DateTime,因此所需的Field验证器将被附加,因为原始表达式是针对日期时间而不是可以为空的日期时间。

因此,下面的解决方案不起作用。

与提问者一样,我也使用了DateTimeModelBinder: Here's the Link

这就是我解决类似情况的方法:

@Html.EditorFor(x => x.NewAssignment.AssignmentEndDate.GetValueOrDefault().Date)

这就是我的DateTime EditorTemplate的样子:

@model DateTime

@Html.TextBox("", Model != default(DateTime) ? Model.ToShortDateString() : String.Empty, new { @class = "datepicker", @maxlength = "10" })