Обработка массивов в данных обратной передачи - MVC3 - PullRequest
2 голосов
/ 01 июля 2011

Я в настоящее время разработчик WebForms, который пытается перейти на MVC. Я очень взволнован MVC и мне действительно весело, но я сталкиваюсь со странной проблемой. Итак, я пытаюсь создать расширенный редактор для «виджета». Я разместил код ниже.

Все выглядит нормально, когда вы добавляете первые 4-5 элементов, но проблема возникает при удалении 2-го элемента. Вот наглядный пример.

Сначала добавьте 4 значения.

enter image description here

Но проблема возникает, когда мы удаляем 2-е значение. Мы заканчиваем с этим ...

enter image description here

Похоже, я не могу понять, почему это свойство действует по-разному в двух следующих строках кода.

@Model.Values[i]
@Html.TextBoxFor(m => m.Values[i])

Я предполагаю, что @Model и (m => m) не ссылаются на один и тот же объект?

Вот мой класс виджетов.

public class Widget
{
    #region Constructor

    public Widget()
    {
        ID = 0;
        Name = string.Empty;
        Values = new List<string>();
    }

    #endregion

    #region Properties

    [Required]
    [Display(Name = "ID")]
    public int ID { get; set; }

    [Required]
    [Display(Name = "Name")]
    public string Name { get; set; }

    [Required]
    [Display(Name = "Values")]
    public List<string> Values { get; set; }

    #endregion
}

Мой контроллер выглядит следующим образом.

public ViewResult EditWidget(int id)
{
    return View(_widgets.GetWidgetByID(id));
}

[HttpPost]
public ActionResult EditWidget(Widget widget)
{
    if (!TryUpdateModel(widget))
    {
        ViewBag.Message = "Error...";
        return View(widget);
    }

    if (Request.Form["AddWidgetValue"] != null)
    {
        widget.Values.Add(Request.Form["TextBoxWidgetValue"]);
        return View("EditWidget", widget);
    }

    if (Request.Form["DeleteWidgetValue"] != null)
    {
        widget.Values.Remove(Request.Form["ListBoxWidgetValues"]);
        return View("EditWidget", widget);
    }

    _widgets.UpdateWidget(widget);
    _widgets.Save();

    return RedirectToAction("Index");
}

И, наконец, мой взгляд.

@model MvcTestApplication.Models.Widget

@{
    ViewBag.Title = "EditWidget";
}

<h2>EditWidget</h2>

<script src="@Url.Content("~/Scripts/jquery.validate.min.js")" type="text/javascript"></script>
<script src="@Url.Content("~/Scripts/jquery.validate.unobtrusive.min.js")" type="text/javascript"></script>

@using (Html.BeginForm()) {
    @Html.ValidationSummary(true)
    <fieldset>
        <legend>Widget</legend>

        @Html.HiddenFor(model => model.ID)

        <div class="editor-label">
            @Html.LabelFor(model => model.Name)
        </div>
        <div class="editor-field">
            @Html.EditorFor(model => model.Name)
            @Html.ValidationMessageFor(model => model.Name)
        </div>

        @for (var i = 0; i < Model.Values.Count; i++)
        {
            @Model.Values[i]
            @Html.TextBoxFor(m => m.Values[i])
            @Html.HiddenFor(m => m.Values[i])
            <br />
        }

        @Html.ListBox("ListBoxWidgetValues", new SelectList(Model.Values), new { style = "width: 100%" })<br />
        @Html.TextBox("TextBoxWidgetValue", string.Empty, new { style = "width: 100%" })
        <input type="submit" value="Add" id="AddWidgetValue" name="AddWidgetValue" class="submitButton" />
        <input type="submit" value="Delete" id="DeleteWidgetValue" name="DeleteWidgetValue" class="submitButton" />

        <p>
            <input type="submit" value="Save" />
        </p>
    </fieldset>
}

<div>
    @Html.ActionLink("Back to List", "Index")
</div>

1 Ответ

4 голосов
/ 01 июля 2011

Причина этого заключается в том, что помощники HTML сначала смотрят опубликованные значения ModelState при связывании, а затем в модели.Это означает, что если в вашем действии контроллера POST вы пытаетесь изменить какое-то значение, и это же значение было частью первоначального запроса на публикацию, помощник HTML будет использовать начальное значение, а не то, которое вы изменили.

Например, вваше действие EditWidget, которое вы выполняете:

if (Request.Form["DeleteWidgetValue"] != null)
{
    widget.Values.Remove(Request.Form["ListBoxWidgetValues"]);
    return View("EditWidget", widget);
}

Вы должны удалить изначально проведенное значение из состояния модели:

if (Request.Form["DeleteWidgetValue"] != null)
{
    var itemToRemove = Request.Form["ListBoxWidgetValues"];
    var index = widget.Values.IndexOf(itemToRemove);
    ModelState.Remove("Values[" + index + "]");
    widget.Values.Remove(itemToRemove);
    return View("EditWidget", widget);
}

Итак, запрос POST содержал:

Values[0] = 1
Values[1] = 2
Values[2] = 3
Values[3] = 4

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

Вы также можете найти следующийсообщение в блоге полезно.Он предназначен для веб-форм ASP.NET MVC 2, но адаптировать его к Razor было бы тривиально.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...