EditorFor on nullable DateTime - "Nullable对象必须有值".

Nic*_*ein 2 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; }
Run Code Online (Sandbox Code Playgroud)

Assignment.cs包含:

public DateTime AssignmentStartDate { get; set; }
public DateTime? AssignmentEndDate { get; set; }
Run Code Online (Sandbox Code Playgroud)

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

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

我的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 />
}
Run Code Online (Sandbox Code Playgroud)

我的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" })
Run Code Online (Sandbox Code Playgroud)

当我尝试加载Create视图时,我在"@ Html.EditorFor(x => x.NewAssignment.AssignmentEndDate.Value)"行中得到了上面提到的异常.

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

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

var newAssignment = new AssignmentViewModel 
                        { 
                            Person = person, 
                            NewAssignment = new Assignment { AssignmentEndDate = DateTime.MinValue } 
                        };
Run Code Online (Sandbox Code Playgroud)

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

我该如何正确处理?

Sco*_*pey 5

问题是,你试图取回AssignmentEndDate.Value.Date,但AssignmentEndDatenull,这会导致这个错误.

由于你的编辑器模板接受了一个DateTime?,你应该传递AssignmentEndDate.换句话说,.Value.Date从视图中删除:

@Html.EditorFor(x => x.NewAssignment.AssignmentEndDate, new { cssClass = "datePicker" })
Run Code Online (Sandbox Code Playgroud)

由于您的编辑器模板正在使用ToShortDateString(),因此无需从截断日期"截断"时间.

更新

关于你想要单独的"日期"和"时间"编辑的愿望:

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

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"})
Run Code Online (Sandbox Code Playgroud)

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

@Html.EditorFor(x => x.NewAssignment.AssignmentEndDate, "DateOnly")
@Html.EditorFor(x => x.NewAssignment.AssignmentEndDate, "TimeOnly")
Run Code Online (Sandbox Code Playgroud)

选择取决于您,以及您是否要将日期和时间部分分开或一起保留,但这就是我要解决此问题的方法.