【问题标题】:MVC3 Razor "For" model - contents duplicatedMVC3 Razor "For" 模型 - 内容重复
【发布时间】:2011-12-14 15:45:04
【问题描述】:

有趣的是,尽管从服务器正确接收数据,但我的 MVC3 razor 表单仍会在 foreach 代码块中呈现重复值。这是我在 MVC3 Razor 中的简单形式...

-- 我的 .cshtml 页面示例

@model List<Category>
@using (@Html.BeginForm("Save", "Categories", FormMethod.Post))
{
foreach (Category cat in Model)
 {
        <span>Test: @cat.CategoryName</span>

        <span>Actual: @Html.TextBoxFor(model => cat.CategoryName)</span>
        @Html.HiddenFor(model => cat.ID)
        <p>---</p>            
 }

  <input type="submit" value="Save" name="btnSaveCategory" id="btnSaveCategory" />
}

我的控制器动作看起来像这样 -

 [HttpPost]
    public ActionResult Save(ViewModel.CategoryForm cat)
    {
       ... save the data based on posted "cat" values (I correctly receive them here)

       List<Category> cL = ... populate category list here
       return View(cL);
    }

上面的保存操作会返回带有正确数据的模型。

提交上述表单后,我希望在完成操作后看到类似于以下类别的值...

Test: Category1, Actual:Category1
Test: Category2, Actual:Category2
Test: Category3, Actual:Category3
Test: Category4, Actual:Category4

但是@Html.TextBoxFor 复制了列表中的第一个值。发布表格后,我看到如下回复。即使我从服务器获得了正确的数据,“实际”值也会重复。

Test: Category1, Actual:Category1
Test: Category2, Actual:Category1
Test: Category3, Actual:Category1
Test: Category4, Actual:Category1

我做错了什么?任何帮助将不胜感激。

【问题讨论】:

    标签: asp.net-mvc-3 razor


    【解决方案1】:

    TextBoxFor 之类的辅助方法旨在与表示单个对象而非对象集合的 ViewModel 一起使用。

    正常的用法是:

    @Html.TextBoxFor(c => c.Name)
    

    c 在方法内部映射到ViewData.Model

    你正在做一些不同的事情:

    @Html.TextBoxFor(c => iterationItem.Name)
    

    方法 internall 仍会尝试使用 ViewData.Model 作为渲染的基础对象,但您打算在迭代项上使用它。该语法虽然对编译器有效,但可以解决这个问题。

    一种解决方法是创建一个对单个项目进行操作的局部视图:在该视图中,您可以使用具有正确语法的 html 助手(第一个示例),然后在 foreach 中调用它,将迭代项目作为参数传递。这应该可以正常工作。

    【讨论】:

      【解决方案2】:

      更好的方法是使用 EditorTemplates。

      在您的表单中,您可以这样做:

      @model List<Category>
      @using (@Html.BeginForm("Save", "Categories", FormMethod.Post))
      {
          @Html.EditorForModel()
          <input type="submit" value="Save" name="btnSaveCategory" id="btnSaveCategory" />
      }
      

      然后,您将在 ~/Views/Shared 文件夹或 Controllers View 文件夹中创建一个名为 EditorTemplates 的文件夹(取决于您是要与整个应用程序共享模板还是仅与此控制器共享模板),然后在在 EditorTemplates 文件夹中,创建一个 Category.cshtml 文件,如下所示:

      @model Category
      <span>Test: @Model.CategoryName</span>
      
      <span>Actual: @Html.TextBoxFor(model => model.CategoryName)</span>
      @Html.HiddenFor(model => model.ID)
      <p>---</p>            
      

      MVC 将自动遍历集合并为其中的每个项目调用您的模板。

      【讨论】:

        【解决方案3】:

        我注意到在视图中使用 foreach 循环会导致文本框的名称属性对于集合中的每个项目都呈现相同的状态。对于您的示例,每个文本框都将使用以下 ID 和 Name 属性呈现:

        <input id="cat_CategoryName" name="cat.CategoryName" value="Category1" type="text">
        

        当您的控制器接收到表单数据集合时,它将无法将集合重构为不同的值。

        解决方案

        1. 我采用的一个很好的模式是将您的视图绑定到您要回发的同一个类。在示例中,模型被绑定到 List&lt;Category&gt;,但控制器 Save 方法接收模型 ViewModel.CategoryForm。我会让它们都一样。

        2. 使用for 循环而不是foreach。 name/id 属性将是唯一的,模型绑定器将能够区分这些值。

        我的最终代码:

        查看

        @model CategoryForm
        @using TestMvc3.Models
        
        @using (@Html.BeginForm("Save", "Categories", FormMethod.Post))
        {
            for (int i = 0; i < Model.Categories.Count; i++)
            {
                <span>Test: @Model.Categories[i].CategoryName</span>
        
                <span>Actual: @Html.TextBoxFor(model => Model.Categories[i].CategoryName)</span>
                @Html.HiddenFor(model => Model.Categories[i].ID)
                <p>---</p>            
            }
        
            <input type="submit" value="Save" name="btnSaveCategory" id="btnSaveCategory" />
        }
        

        控制器

        public ActionResult Index()
        {
            // create the view model with some test data
            CategoryForm form = new CategoryForm()
            {
                Categories = new List<Category>()
            };
        
            form.Categories.Add(new Category() { ID = 1, CategoryName = "Category1" });
            form.Categories.Add(new Category() { ID = 2, CategoryName = "Category2" });
            form.Categories.Add(new Category() { ID = 3, CategoryName = "Category3" });
            form.Categories.Add(new Category() { ID = 4, CategoryName = "Category4" });
        
            // pass the CategoryForm view model
            return View(form);
        }
        
        [HttpPost]
        public ActionResult Save(CategoryForm cat)
        {
            // the view model will now have the correct categories
            List<Category> cl = new List<Category>(cat.Categories);
        
            return View("Index", cat);
        }
        

        【讨论】:

          猜你喜欢
          • 2012-05-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多