Html.BeginForm的奇怪行为

时间:2012-01-12 20:26:35

标签: c# asp.net-mvc-3 forms post

让我们创建空的asp.net mvc 3应用程序。 代码是

namespace MvcApplication1.Controllers
{
public class MyModel
{
    public int Id { get; set; }
}

public class HomeController : Controller
{
    public ActionResult Index()
    {
        return Index1(new MyModel() {Id = 100});
    }
    public ActionResult Index1(MyModel model)
    {
        var nm = new MyModel();
        nm.Id = model.Id + 1;
        return View("test", nm);
    }
}

让我们创建名为test的共享视图。查看代码

@using MvcApplication1.Controllers
@model MyModel

@if (Model != null)
{
    using (Html.BeginForm("Index1", "Home", FormMethod.Post, new { autocomplete = "off" }))
    {
    <div id="compareQuestions">
        <p>@Model.Id</p>
        @Html.HiddenFor(m => m.Id)
        @Html.TextBoxFor(m => m.Id)
        <input type="submit" value="save"/>
    </div>
    }
}

当我们第一次发布表单时一切正常,但是当它在文本框中的第一个帖子值之后重新加载时不正确。如果我们更改此值并在控制器上保存帖子,我们会得到具有不正确值的模型,但不会输入。这怎么可能?

2 个答案:

答案 0 :(得分:2)

<p>@Model.Id</p>@Html.HiddenFor(m => m.Id)之间存在显着差异。

当您发布表单时,所有POST的值都存储在ModelState中 当您使用HtmlHelper方法时,他们首先从ModelState中提取值。如果ModelState不包含值,则会查看实际的m.Id

因此,当您第一次获得表单时,没有ModelState。但是,一旦您发布表单,它会将值存储到ModelState,因此隐藏的输入使用该值而不是m.Id

如果您希望始终使用m.Id,则需要清除控制器中的ModelState

public ActionResult Index1(MyModel model)
{
    ModelState.Clear();
    ...

答案 1 :(得分:1)

看起来这是正确的行为,因为您已经编写了您的操作方法。在视图中,您要为同一个模型属性呈现文本框和隐藏字段。

因此,当您在帖子中将Id增加1时,您将在文本框中增加值并在隐藏字段中增加。

如果您希望文本框和隐藏字段在第二篇文章后具有不同的值,则您需要在模型上使用不同的属性。

另一个问题可能是,由于您有2个不同的<input元素具有相同的名称,因此无法确定表单是否会从隐藏字段或文本框中发送值。同样,如果这两个字段应具有不同的值,则它们需要在模型上具有不同的属性。如果您希望它们始终具有相同的值,请在视图中放置TextBox或Hidden,但不能同时放置两者。