MVC 5 Viewmodel 绑定有效,但 post 背面已部分填充

MVC 5 Viewmodel binding works but post back is partial filled

我为 HttpGet 设置了一个无参数的 Index,它可以工作。但是当我 post 它调用 IndexHttpPost 版本并传入视图模型 object 时,但其中只有下拉列表的值。其余为空(产品,标题)

[HttpPost]
public ActionResult Index(ProductsViewModel pvm)
{
    // breakpoint on line 36, shows that pvm.Title is null and Products too.
    return View(pvm);
}

我的可编译和 运行 示例可以从我的 OneDrive 下载 http://1drv.ms/1zSsMkr

我的看法:

@model KleinKloteProductOverzicht.Models.ProductsViewModel
@using (Html.BeginForm("Index", "Products"))
{
<h2>@Html.DisplayFor(m => m.Title)</h2>
<input type="submit" value="post dit" /><br/>
<div class="row">
    <div class="col-lg-2 col-md-2">
        @Html.DropDownListFor(x => x.CurrentSort, EnumHelper.GetSelectList(typeof(SortOptions)), new { @class = "multiselect"})
    </div>
</div>
if (Model.Products.Count() > 0)
{
    <div class="row">
        @foreach (var item in Model.Products)
        {
            @Html.DisplayFor(i => item.Name);
        }
    </div>
}
}

如果我有这个视图模型:

public class ViewModel
{
    public string Name {get;set;}
    public string SelectedLocation {get;set;}

    public IEnumerable<SelectListItem> Locations {get;set;}
}

你的动作是这样的:

public ActionResult MyForm()
{
    var vm = new ViewModel
    {
        Locations = context.Locations.ToList() // Some database call
    }

    return View(vm);
}

[HttpPost]
public ActionResult MyForm(ViewModel vm)
{
    vm.Locations // this is null
}

这是null,因为模型绑定器找不到正在设置其数据的表单控件。

<form> 必须在视图中设置一些数据,以便模型绑定器提取它。

<form>
    Name: <input type="text" id="name" />
</form>

这将在视图模型上设置 Name 属性,因为模型绑定可以看到表单控件的 id 并使用它来知道绑定到什么。

因此,就您的观点而言,您需要确保使用 @using(Html.BeginForm())

包装您想要 post 返回服务器的任何内容

反正这是我的猜测。

嗯,您似乎对 [HttpPost] 和表单标签如何相互交互感到困惑。

您会看到,当 .NET MVC 在您的控制器操作中绑定您的参数时,它会尝试从请求中派生该数据。对于 [HttpGet],它通过查看查询字符串来完成此操作。

对于 [HttpPost] 调用,它还会查看 Request.Form。此变量填充了您提交的表单中所有输入字段的值。

现在,这是您的观点:

@using (Html.BeginForm("Index", "Products"))
{
    <h2>@Html.DisplayFor(m => m.Title)</h2>
    <input type="submit" value="post dit" /><br/>
    <div class="row">
        <div class="col-lg-2 col-md-2">
            @Html.DropDownListFor(x => x.CurrentSort, EnumHelper.GetSelectList(typeof(SortOptions)), new { @class = "multiselect" })
        </div>
    </div>
    if (Model.Products.Count() > 0)
    {
        <div class="row">
            @foreach (var item in Model.Products)
            {
                @Html.DisplayFor(i => item.Name);
            }
        </div>
    }
}

您只有一个 select 标签(由 Dropdownlistfor 生成)但没有其他输入。这就是 .NET MVC 无法为您的视图模型推断任何其他数据的原因。

如果你改变你的看法:

@model KleinKloteProductOverzicht.Models.ProductsViewModel

@using (Html.BeginForm("Index", "Products"))
{
    <h2>@Html.DisplayFor(m => m.Title)</h2>
    <input type="submit" value="post dit" /><br/>
    <div class="row">
        <div class="col-lg-2 col-md-2">
            @Html.DropDownListFor(x => x.CurrentSort, EnumHelper.GetSelectList(typeof(SortOptions)), new { @class = "multiselect" })
        </div>
    </div>
    if (Model.Products.Count() > 0)
    {
        <div class="row">
            @for (var i = 0; i < Model.Products.Count; i++)
            {
                @Html.DisplayFor(model => model.Products[i].Name)
                @Html.HiddenFor(model => model.Products[i].ID)
            }
        </div>
    }

}

您会看到我为产品 ID 添加了隐藏输入 (<input type="hidden">)。请注意,产品名称仍然为空。

我建议您遵循有关 .NET MVC 的教程并阅读其背后的一些概念,因为您问这个问题这一事实表明您还有很多东西要学。

祝你好运!

P.S。最后一个提示:@Html.Blablabla 直接写入您的视图。你通常不需要那个“;”最后,因为它将在您生成的 html 中。

您的 属性 未与 "postable" 控件相关联,因此它不会与表单数据一起提交。如果您真的想在 Title 属性 中获取值,只需将其设置为隐藏输入即可。

 @Html.HiddenFor(m => m.Title)

提交 form 时不会发布 label,但会发布 input。这正是 HiddenFor 所做的;它创建了一个隐藏的 input 元素,该元素将被 form 提交拾取。