简体   繁体   English

处理回发数据中的数组 - MVC3

[英]Handling array's in post back data - MVC3

I'm current a WebForms developer that is trying to move to MVC.我目前是一名正在尝试迁移到 MVC 的 WebForms 开发人员。 I'm super excited about MVC and I'm really have fun but I'm running into a weird issue.我对 MVC 感到非常兴奋,我真的很开心,但我遇到了一个奇怪的问题。 So what I'm trying to do is create an advanced editor for a "widget".所以我想做的是为“小部件”创建一个高级编辑器。 I've posted the code below.我已经发布了下面的代码。

Everything appears to work fine when you add the first 4-5 items but the problem occurs when you delete the 2nd item.当您添加前 4-5 个项目时,一切似乎都可以正常工作,但是当您删除第二个项目时会出现问题。 Here is a visual example.这是一个视觉示例。

First add the 4 values.首先添加 4 个值。

在此处输入图像描述

But the problem occurs when we delete the 2nd value.但是当我们删除第二个值时就会出现问题。 We end up with this...我们最终得到这个...

在此处输入图像描述

What I cannot seem to understand is why does this property act different between the two following lines of code.我似乎无法理解的是为什么这个属性在以下两行代码之间表现不同。

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

My guess is that the @Model and (m =>m) do not reference the same object?我的猜测是@Model 和 (m =>m) 没有引用相同的 object?

Here is my widget class.这是我的小部件 class。

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
}

My controller looks like this.我的 controller 看起来像这样。

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");
}

And finally my view.最后是我的观点。

@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>

The reason for this happening is because HTML helpers first look at ModelState posted values when binding and then in model.发生这种情况的原因是因为 HTML 助手在绑定时首先查看 ModelState 发布的值,然后在 model 中查看。 This means that if inside your POST controller action you try to modify some value and this same value was part of the initial post request the HTML helper will use the initial value and not the one you modified.这意味着,如果在您的 POST controller 操作中您尝试修改某个值,并且该相同值是初始发布请求的一部分,则 HTML 助手将使用初始值,而不是您修改的值。

For example in your EditWidget action you are doing this:例如,在您的 EditWidget 操作中,您正在执行以下操作:

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

You should remove the initially posted value from the model state:您应该从 model state 中删除最初发布的值:

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);
}

So the POST request contained:所以 POST 请求包含:

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

Inside the POST action you removed for example the second item so you should also remove it from the model state or the TextBoxFor helper will still use the old one.在您删除的 POST 操作中,例如第二个项目,因此您还应该将其从 model state 或 TextBoxFor 帮助程序中删除,仍将使用旧项目。

You may also find the following blog post useful.您可能还会发现以下博客文章很有用。 It's for ASP.NET MVC 2 WebForms but it would be trivial to adapt it to Razor.它适用于 ASP.NET MVC 2 WebForms,但将其适应 Razor 将是微不足道的。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM