MVC3 — Проблема с использованием редакторов

#asp.net-mvc-3 #razor #mvc-editor-templates

#asp.net-mvc-3 #razor #mvc-editor-templates

Вопрос:

Если бы это была проблема с MVC3, там были бы сообщения об этом, но я не могу найти ни одного. Должно быть, я делаю что-то не так. У меня есть простое представление (Index.cshtml), которое выполняет итерацию по списку с использованием цикла for. На каждой итерации я вывожу два текстовых ввода со значениями из одного из элементов списка.

 @{Html.BeginForm();}
@Html.Encode("n")
@for (int i = 0; i < Model.SortOptions.Count; i   )
{
    @Html.TextBoxFor(m => m.SortOptions[i].ColumnName);
    @Html.Encode("n");
    @Html.TextBoxFor(m => m.SortOptions[i].Direction);
    @Html.Encode("n");
}
<input type="submit" value="Submit" />
@{Html.EndForm();}
  

У меня есть два контроллера для просмотра, один для запросов GET и один для POST. Версия POST добавляет в список элементы, отличные от версии GET. Вот тут-то и возникает проблема. После перезагрузки страницы текстовые поля имеют то же значение, что и при загрузке страницы в GET.

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

 @{Html.BeginForm();}
@Html.Encode("n")
@for (int i = 0; i < Model.SortOptions.Count; i   )
{
    var columnNameName = string.Format("SortOptions[{0}].ColumnName", i);
    var columnNameID = string.Format("SortOptions_{0}__ColumnName", i);
    var directionName = string.Format("SortOptions[{0}].Direction", i);
    var directionID = string.Format("SortOptions_{0}__Direction", i);

<input type="hidden" name="@columnNameName" id="@columnNameID" value="@Model.SortOptions[i].ColumnName" />
<input type="hidden" name="@directionName" id="@directionID" value="@Model.SortOptions[i].Direction" />

}
<input type="submit" value="Submit" />
@{Html.EndForm();}
  

Я прошелся по коду, чтобы убедиться, что модель содержит ожидаемые значения на момент их отправки в представление. Я даже проверил значения списка, пройдясь по коду в представлении. Кажется, что он имеет правильные значения, но когда я просматриваю его в браузере, у него есть значения, которые должны соответствовать моменту, когда страница ответила на запрос GET. Это проблема с шаблонами редактора? Я только начал использовать mvc3 и движок razor, поэтому я многого не знаю. Буду признателен за любую помощь.

—— ОБНОВЛЕНИЕ: ДОБАВЛЕН код КОНТРОЛЛЕРА —-

     [HttpGet]
    public ActionResult Index()
    {
        var inv = new InventoryEntities();
        var model = new IndexModel(inv);
        model.SortOptions = new List<SortOption>();
        model.SortOptions.Add(new SortOption { ColumnName = "Model", Direction = SortDirection.Ascending });
        model.SortOptions.Add(new SortOption { ColumnName = "Make", Direction = SortDirection.Ascending });
        //Load data
        model.LoadEquipmentList();

        return View(model);
    }


    [HttpPost]
    [OutputCache(Duration = 1)]
    public ActionResult Index(List<SortOption> sortOptions, SortOption sort)
    {
        var inv = new InventoryEntities();
        var model = new IndexModel(inv);
        ModelState.Remove("SortOptions");
        model.SortOptions = new List<SortOption>();
        model.SortOptions.Add(new SortOption { ColumnName = "Type", Direction = SortDirection.Descending });
        model.SortOptions.Add(new SortOption { ColumnName = "SubType", Direction = SortDirection.Descending });
        model.EquipmentList = new List<EquipmentListItem>();
        model.EquipmentList.Add(new EquipmentListItem { ID = 3, AssignedTo = "Mike", Location = "Home", Make = "Ford", Model = "Pinto", Selected = false, SubType = "Car", Type = "Vehicle" });

        return View(model);
    }
  

Комментарии:

1. Можете ли вы опубликовать код действия контроллера?

2. Теперь опубликован код контроллера.

Ответ №1:

Помните, что помощники Html, такие как TextBoxFor , сначала используют состояние модели при привязке своих значений, а затем модель. Давайте рассмотрим очень простой пример, чтобы проиллюстрировать, что это значит:

 public class HomeController : Controller
{
    public ActionResult Index()
    {
        return View(new MyViewModel { Name = "foo" });
    }

    [HttpPost]
    public ActionResult Index(MyViewModel model)
    {
        model.Name = "bar";
        return View(model);
    }
}
  

и представление:

 @model MyViewModel
@using (Html.BeginForm())
{
    @Html.TextBoxFor(x => x.Name)
    <input type="submit" value="OK" />
}
  

Теперь, когда вы отправляете форму, вы ожидаете, что значение в текстовом поле изменится на "bar" , поскольку это то, что вы ввели в свое действие POST, но значение не меняется. Это потому, что в состоянии модели уже есть значение с ключом Name , которое содержит то, что ввел пользователь. Итак, если вы хотите, чтобы это сработало, вам нужно удалить исходное значение из состояния модели:

 [HttpPost]
public ActionResult Index(MyViewModel model)
{
    // remove the original value if you intend to modify it here
    ModelState.Remove("Name");
    model.Name = "bar";
    return View(model);
}
  

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

Комментарии:

1. Я пытался использовать ModelState. Удалить, безуспешно. Я получаю те же результаты. Я обновлю свой пост кодом для двух методов контроллера.

2. Хорошо, это было в основном проблемой. Я все еще не до конца понимаю, как работает modelstate, но если я добавлю «ModelState. Очистить();» в начале метода контроллера проблема устраняется. Спасибо, что указали мне правильное направление.

Ответ №2:

Мне бросается в глаза пара вещей — не видя немного больше, трудно сказать, но … оба они могут быть переписаны как таковые. Дополнительные @ символы не нужны.

 @using(Html.BeginForm()) {
    Html.Encode("n")
    for (int i = 0; i < Model.SortOptions.Count; i   ) {
        Html.TextBoxFor(m => m.SortOptions[i].ColumnName);
        Html.Encode("n");
        Html.TextBoxFor(m => m.SortOptions[i].Direction);
        Html.Encode("n");
    }
    <input type="submit" value="Submit" />
}


@using (Html.BeginForm()) { 
    Html.Encode("n");
    for (int i = 0; i < Model.SortOptions.Count; i   ) {
        var columnNameName = string.Format("SortOptions[{0}].ColumnName", i);
        var columnNameID = string.Format("SortOptions_{0}__ColumnName", i);
        var directionName = string.Format("SortOptions[{0}].Direction", i);
        var directionID = string.Format("SortOptions_{0}__Direction", i);

        <input type="hidden" name="@columnNameName" id="@columnNameID" value="@Model.SortOptions[i].ColumnName" />
        <input type="hidden" name="@directionName" id="@directionID" value="@Model.SortOptions[i].Direction" />

    }
    <input type="submit" value="Submit" />
}
  

В остальном ваш материал выглядит правильно, и я не вижу ничего неправильного в своей голове.

Комментарии:

1. Спасибо за совет по использованию @. Я использовал MVC2 для двух проектов, но это первый проект, использующий MVC3 и razor.