在同一父视图上多次使用一个部分视图

时间:2011-06-27 11:18:17

标签: asp.net-mvc-3 model-binding

我正在使用MVC3剃须刀。我有一个场景,我必须在同一父视图上多次使用局部视图。我遇到的问题是,当父视图被渲染时,它会在这些部分视图中生成相同的名称和输入控件的ID。由于我的部分视图被绑定到不同的模型,当视图回发到“保存”时它崩溃了。任何想法如何使控件ID /名称唯一,可能是一些如何前缀?

等待

Nabeel

2 个答案:

答案 0 :(得分:6)

我个人更喜欢使用编辑器模板,因为他们会照顾这个。例如,您可以使用以下视图模型:

public class MyViewModel
{
    public ChildViewModel Child1 { get; set; }
    public ChildViewModel Child2 { get; set; }
}

public class ChildViewModel
{
    public string Foo { get; set; }
}

和以下控制器:

public class HomeController : Controller
{
    public ActionResult Index()
    {
        var model = new MyViewModel
        {
            Child1 = new ChildViewModel(),
            Child2 = new ChildViewModel(),
        };
        return View(model);
    }

    [HttpPost]
    public ActionResult Index(MyViewModel model)
    {
        return View(model);
    }
}

并在Index.cshtml视图中:

@model MyViewModel
@using (Html.BeginForm())
{
    <h3>Child1</h3>
    @Html.EditorFor(x => x.Child1)

    <h3>Child2</h3>
    @Html.EditorFor(x => x.Child2)
    <input type="submit" value="OK" />
}

,最后一部分是编辑器模板(~/Views/Home/EditorTemplates/ChildViewModel.cshtml):

@model ChildViewModel

@Html.LabelFor(x => x.Foo)
@Html.EditorFor(x => x.Foo)

使用EditorFor,您可以包含主视图模型的不同属性的模板,并生成正确的名称/ ID。除此之外,您还可以在POST操作中正确填充视图模型。

答案 1 :(得分:2)

还有另一种选择:

  1. 为PartialView添加前缀
  2. 绑定模型,删除前缀
  3. 对于1,在视图中设置前缀:

    ViewContext.ViewData.TemplateInfo.HtmlFieldPrefix = "prefix";
    

    对于2,您可以使用UpdateModel恢复数据,如下所示:

    UpdateModel(producto, "prefix");
    

    这不是很明智,因为您的操作不会将数据作为参数接收,而是稍后更新模型。这有几个不便之处:1)通过查看其签名并不清楚您的操作需要什么2)为单元测试提供动作输入并不容易3)操作易受溢出参数(用户提供的参数)的影响不应该存在并映射到模型。)

    但是,对于2,还有另一种选择:注册一个自定义模型绑定器,允许您删除前缀。自定义Model Binder必须知道它。

    一个很好的解决方案就在这个SO Q&amp; A:How to handle MVC model binding prefix with same form repeated for each row of a collection?但是它有一点缺陷:如果你在局部视图中添加一个名为“__prefix”的隐藏字段,你将它呈现几次在局部视图中,该ID将在页面中的几个不同元素中重复,这是不允许的,并且可能会引起一些麻烦。提供前缀的最重要原因之一是精确地呈现与实体的多个实例的部分视图相同的“编辑”视图。即这会发生在像gmail这样的页面中,您可以在其中一次编辑多封电子邮件。

    这个问题有几种可能的解决方案。

    其中一个是提供前缀作为查询字符串或routedata值,而不是作为表单字段,以避免Id冲突,并且可以由模型绑定器找到。 (它可以始终具有相同的名称)。

    另一个解决方案是使用具有固定模式的隐藏字段,但对于每个渲染视图都是不同的。前缀可以遵循这种模式的唯一性:“PP $ ActionControllerId”,如“PP $ EditProduct23”,它对于每个渲染视图都是唯一的,并且可以在请求参数之间轻松找到,以查找以“PP $”开头的参数。 / p>

    最终解决方案是仅在视图中创建前缀,而不是在任何类型的请求参数中提供它。 Model绑定器必须查找检查请求参数名称的前缀,直到找到其前缀遵循该模式的前缀。

    当然,自定义的ModelBinder必须适应所选的约定。