EditorFor для nullable DateTime - «Обнуляемый объект должен иметь значение». - PullRequest
2 голосов
/ 20 декабря 2011

Я пытаюсь отобразить форму, которая позволяет пользователю вводить новое назначение для человека. Я использую DateTime.cshtml EditorTemplate для обработки значений DateTime для назначения. Необнуляемый DateTime работает отлично. Обнуляемый DateTime вызывает «InvalidOperationException: Nullable объект должен иметь значение».

У меня есть простая модель представления, которая выглядит следующим образом:

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 />
}

Мой 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 => x.NewAssignment.AssignmentEndDate.Value)".

Возможно, вам интересно, почему я передаю AssignmentEndDate.Value.Date вместо того, чтобы просто передавать AssignmentEndDate; причина в том, что я пытаюсь добраться до точки, где я разделяю DateTime на Date и поле TimeOfDay и рекомбинирую их с DateTimeModelBinder. Я использую технику, аналогичную , показанной здесь и здесь .

Я могу обойти ошибку, изменив метод контроллера Create () для создания экземпляра ViewModel с AssignmentEndDate, установленным в DateTime.MinValue, но это кажется совершенно неправильным для обнуляемого DateTime:

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

Что-то странное происходит после того, как я «обхожу» ошибку, предоставив значение для обнуляемого DateTime; необязательное свойство DateTime с нулевым значением (AssignmentEndDate.Date) не проходит проверку на стороне клиента. При попытке отправить форму поле подсвечивается красным.

Как я могу справиться с этим правильно?

Ответы [ 3 ]

5 голосов
/ 21 декабря 2011

Проблема в том, что вы пытаетесь получить AssignmentEndDate.Value.Date, но AssignmentEndDate равно null, что приводит к этой ошибке.

Поскольку ваш шаблон редактора принимает DateTime?, вам нужно просто передать AssignmentEndDate. Другими словами, удалите .Value.Date из вида:

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

Поскольку в вашем шаблоне редактора используется 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"})

2 - Вы можете разделить вышеуказанную функциональность на 2 отдельных редактора: «DateOnly» и «TimeOnly». Затем обновите свой вид, чтобы вызвать обоих редакторов:

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

Выбор за вами, хотите ли вы, чтобы части даты и времени были разделены или вместе, но именно так я бы решил эту проблему.

2 голосов
/ 02 июля 2013

создайте DateTime.cshtml в папке Shared / DisplayTemplate

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

это поддерживает метаданные из примечаний к данным, которые будут использоваться, если они найдены.

0 голосов
/ 09 февраля 2012

ОБНОВЛЕНИЕ: GetValueOrDefault обрабатывает его как DateTime, и, следовательно, обязательные валидаторы поля присоединяются, потому что исходное выражение для даты и времени не может быть равно дате и времени.

Поэтому приведенное ниже решение не работает.

Как и у автора, я также использовал DateTimeModelBinder отсюда: Вот ссылка

Вот как я решил похожую ситуацию:

@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" })
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...