MVC3模型绑定 - 将列表绑定到隐藏字段

3

我有一个特殊的问题 - 我有一个包含列表的ViewModel,用于显示一系列图像:

public List<int> TrackerKeys { get; set; }

此处在页面的两个位置使用:

@for (int i = 0; i < Model.TrackerKeys.Count(); i++)
{ 
    @Html.GenerateImage(PageModes.Http, Model.TrackerKeys[i])
}

And also

@for (int i = 0; i < Model.TrackerKeys.Count(); i++)
{ 
    @Html.HiddenFor(model => model.TrackerKeys[i])
}

这是在一个表单中 - 当表单提交时,如果发生验证错误,则TrackerKeys属性会更新为一组新的随机数字。我传递回先前的列表,以确保用户不再看到相同的图像。

TrackerKeys已正确设置并传回视图。

我的问题是:

图像根据列表中的新值正确显示新图像

然而

隐藏字段的值未更新为新值 - 它们保留原始值。

有任何想法吗?这是MVC3的错误吗?任何输入将不胜感激。谢谢。

编辑

提交前的HTML:

<img alt="Security Character" height="35" src="http://localhost:51414/content/imagescss/26.gif" width="35" />
<img alt="Security Character" height="35" src="http://localhost:51414/content/imagescss/33.gif" width="35" />
<img alt="Security Character" height="35" src="http://localhost:51414/content/imagescss/8.gif" width="35" />
<img alt="Security Character" height="35" src="http://localhost:51414/content/imagescss/30.gif" width="35" />
<img alt="Security Character" height="35" src="http://localhost:51414/content/imagescss/6.gif" width="35" />
<img alt="Security Character" height="35" src="http://localhost:51414/content/imagescss/18.gif" width="35" />  

而且
<input id="TrackerKeys_0_" name="TrackerKeys[0]" type="hidden" value="26" />
<input id="TrackerKeys_1_" name="TrackerKeys[1]" type="hidden" value="33" />
<input id="TrackerKeys_2_" name="TrackerKeys[2]" type="hidden" value="8" />
<input id="TrackerKeys_3_" name="TrackerKeys[3]" type="hidden" value="30" />
<input id="TrackerKeys_4_" name="TrackerKeys[4]" type="hidden" value="6" />
<input id="TrackerKeys_5_" name="TrackerKeys[5]" type="hidden" value="18" />

在这篇文章之后: 在此处更正新值...
<img alt="Security Character" height="35" src="http://localhost:51414/content/imagescss/16.gif" width="35" />
<img alt="Security Character" height="35" src="http://localhost:51414/content/imagescss/20.gif" width="35" />
<img alt="Security Character" height="35" src="http://localhost:51414/content/imagescss/11.gif" width="35" />
<img alt="Security Character" height="35" src="http://localhost:51414/content/imagescss/19.gif" width="35" />
<img alt="Security Character" height="35" src="http://localhost:51414/content/imagescss/26.gif" width="35" />
<img alt="Security Character" height="35" src="http://localhost:51414/content/imagescss/15.gif" width="35" /> 

并且仍然保留旧的值...

(这句话不太清楚上下文,如有需要请提供更多信息)
<input id="TrackerKeys_0_" name="TrackerKeys[0]" type="hidden" value="26" />
<input id="TrackerKeys_1_" name="TrackerKeys[1]" type="hidden" value="33" />
<input id="TrackerKeys_2_" name="TrackerKeys[2]" type="hidden" value="8" />
<input id="TrackerKeys_3_" name="TrackerKeys[3]" type="hidden" value="30" />
<input id="TrackerKeys_4_" name="TrackerKeys[4]" type="hidden" value="6" />
<input id="TrackerKeys_5_" name="TrackerKeys[5]" type="hidden" value="18" />

控制器动作

[HttpPost]
    public ActionResult EmployerRegistration(EmployerViewModel Model)
    {
        if (ModelState.IsValid)
        {
            //do bits here
        }

        Model.TrackerKeys = Helper.GenerateNewNumbers(Model.TrackerKeys); 
        return View(Model);
    }

你能提供生成的HTML吗?我怀疑你的HTML元素没有相同的名称/ID,因此它无法将其识别为列表(即使它可以工作)。 - Joakim
你能发布你的控制器动作吗? - nemesv
我会将控制器操作设置为POST。 - Carl
1个回答

13

这是MVC3的一个bug吗?

不,这是设计上的,也是ASP.NET MVC中所有HTML助手的工作原理。HTML助手(例如Html.TextBoxForHtml.HiddenFor等)在绑定值时首先查看ModelState,之后再查看Model。因此,如果您打算在POST控制器操作中修改模型的某个属性,而该属性是POST主体的一部分,则必须首先从ModelState中删除旧值:

[HttpPost]
public ActionResult EmployerRegistration(EmployerViewModel Model)
{
    if (ModelState.IsValid)
    {
        //do bits here
    }

    // we clear all values from the modelstate => this will ensure that
    // the helpers will use the values from the model and not those that
    // were part of the initial POST.
    ModelState.Clear();
    Model.TrackerKeys = Helper.GenerateNewNumbers(Model.TrackerKeys); 
    return View(Model);
}

或者如果您不想清除整个ModelState(因为这将删除所有值以及可能与它们相关的任何相应的modelstate错误),您可以仅删除您实际修改的那些键:

[HttpPost]
public ActionResult EmployerRegistration(EmployerViewModel Model)
{
    if (ModelState.IsValid)
    {
        //do bits here
    }

    for (var i = 0; i < Model.TrackerKeys.Count; i++)
    {
        ModelState.Remove(string.Format("TrackerKeys[{0}]", i));
    }
    Model.TrackerKeys = Helper.GenerateNewNumbers(Model.TrackerKeys); 
    return View(Model);
}

一如既往的最好和简单的解释...谢谢Darin。 - Sugar Bowl

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接