После вызова RemoveAt() в списке кажется, что он работает, но когда EditorFor отображает обновленный список, удаленное поле по-прежнему отображается

Я пытаюсь настроить представление, в котором пользователь может добавлять и удалять из списка людей. Когда я отлаживаю, после удаления элемента с помощью RemoveAt(i) список обновляется правильно, и когда я проверяю модель во время создания представления, удаленного элемента там нет. Однако после того, как я вызываю EditorFor(x => name) в цикле for, который отображает каждый элемент в списке, отображается правильное количество элементов, но значения не совпадают с тем, что содержится в модели.

Я использую методы из этого ответа для отображения каждого элемента.

Соответствующий код:

Контроллер:

[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Persons(IList<Person> persons, string command)
{
    if (!ModelState.IsValid && !command.StartsWith("Delete"))
        return View(persons);
    if (command == "AddNew")
    {
        List<Person> newPersons = persons?.ToList() ?? new List<Person>();
        newPersons.Add(new Person());
        return View(newPersons);
    }
    if (command.StartsWith("Delete"))
    {
        if (int.TryParse(command.Substring(6), out int i))
            persons.RemoveAt(i);
        else
            ModelState.AddModelError("", "There was an error deleting the person.");
        return View(persons);
    }
    return RedirectToAction(command == "Back" ? "Index" : "Summary");
}

Person.cs (модель)

private string firstName;
private string middleName;
private string lastName;

[Required(AllowEmptyStrings = false)]
[Display(Name = "First Name")]
public string FirstName
{
    get => firstName;
    set => firstName = value?.Trim();
}

[Display(Name = "Middle Name")]
public string MiddleName
{
    get => middleName;
    set => middleName = value?.Trim();
}

[Required(AllowEmptyStrings = false)]
[Display(Name = "Last Name")]
public string LastName
{
    get => lastName;
    set => lastName = value?.Trim();
}

Лица.cshtml:

@model IEnumerable<Person>
<div class="text-center">
    <button type="submit" name="command" value="AddNew" class="btn btn-primary btn-lg">
        Add another person
    </button>
</div>
{
    int i = 0;
    foreach (Person person in Model)
    {
        @Html.EditorFor(x => person, "PersonTemplate", $"Persons[{i++}]")
    }
}
<script type="text/javascript>
$(document).on("click", "button[value='Delete']", function() {
    const r = $(this).parent().prev().find("select").attr("name");
    const s = r.substring(8, r.indexOf("]"));
    $(this).val(`Delete${s}`);
})
</script>

PersonTemplate.cshtml:

<div class="row px-3 pb-3">
    <div class="col-lg-3 col-md-6">
        @Html.LabelFor(x => x.FirstName, new { @class = "required" })
        @Html.EditorFor(x => x.FirstName, new { htmlattributes = new { @class = "form-control" } })
        @Html.ValidationMessageFor(x => x.FirstName)
    </div>
    <div class="col-lg-3 col-md-6">
        @Html.LabelFor(x => x.MiddleName)
        @Html.EditorFor(x => x.MiddleName, new { htmlattributes = new { @class = "form-control" } })
    </div>
    <div class="col-lg-4 col-md-7">
        @Html.LabelFor(x => x.LastName, new { @class = "required" })
        @Html.EditorFor(x => x.LastName, new { htmlattributes = new { @class = "form-control" } })
        @Html.ValidationMessageFor(x => x.LastName)
    </div>
</div>
<button type="submit" name="command" value="Delete" class="btn btn-outline-danger">
    Delete
</button>

Добавление нового пустого элемента в список работает нормально. Удаление элемента работает, вплоть до команды EditorFor. Вот пример сценария, через который я прохожу:

  • на экране 3 имени: Боб Смит, Ларри Джонс, Энн Уокер.
  • Я нажимаю кнопку «Удалить» рядом с Ларри Джонсом.
  • По мере того, как я выполняю действие контроллера, command = «Удалить1», поэтому я знаю, что javascript, который определяет, какой из них нужно удалить, работает.
  • int.TryParse() возвращает i = 1, поэтому я знаю, что эта часть тоже работает.
  • Когда я просматриваю объект persons после строки RemoveAt(i), в списке есть два объекта Person: Bob Smith и Anne Walker.
  • Когда я вхожу в представление и проверяю объект модели, есть два объекта Person: Боб Смит и Энн Уокер.
  • В цикле for при вызове EditorFor() первым объектом Person, который отправляется в шаблон, является Боб Смит. Второй объект Person — Энн Уокер.
  • Вот ключевой момент, который я не понимаю: в PersonTemplate.cshtml this.Model имеет FirstName = "Anne" и LastName = "Walker", но MvcHtmlString, сгенерированный @Html.EditorFor(x => x.FirstName), возвращает следующее:
<input class="text-box single-line" id="Persons_1__FirstName" name="Persons[1].FirstName" type="text" value="Larry" />
  • @Html.EditorFor(x => x.LastName) возвращает:
<input class="text-box single-line" id="Persons_1__LastName" name="Persons[1].LastName" type="text" value="Jones" />

Что случилось с Энн Уокер? В PersonTemplate this.Model по-прежнему показывает FirstName = "Anne" и LastName = "Walker", но вместо них во входных значениях используется Ларри Джонс.

Это происходит независимо от того, какой из них я удаляю в списке. Если у меня есть 5 человек в списке, и я удаляю человека № 1, то в представлении отображаются лица 1, 2, 3 и 4. Если я удаляю человека 4, он по-прежнему отображает людей 1, 2, 3 и 4. Если Я удаляю человека 5, он отображает людей 1, 2, 3 и 4. Почему он не отображает правильное значение из модели?


person John    schedule 09.10.2019    source источник
comment
Когда вы удаляете элемент из массива, все элементы над удаленным элементом перемещаются на один индекс вниз. Итак 1) А 2) Б 3) В 4) Г 5) Д. При удалении пункта 3 получается 1) А 2) Б 3) Г 4) Д.   -  person jdweng    schedule 09.10.2019
comment
@jdweng Верно, но даже если я передам список (после удаления элемента) в новый список и передам его в представление, исходные элементы все равно будут отображаться. EditorFor не соответствует тому, что содержит модель.   -  person John    schedule 09.10.2019
comment
Тогда модель при создании данных и модель при приведении не совпадают.   -  person jdweng    schedule 10.10.2019
comment
@jdweng Когда я отлаживаю и просматриваю модель в представлении, она не содержит имя, которое было удалено в контроллере. Тем не менее, он по-прежнему генерирует имя, которое было удалено.   -  person John    schedule 10.10.2019
comment
Я понял это - мне пришлось очистить ModelState, после чего это сработало.   -  person John    schedule 18.10.2019