2011-04-15 88 views
2

缺少在POST操作中的未填充值中恢复的缺陷?复合视图模型和更新模型

控制器

public ActionResult Index() 
{ 
    var productPageViewModel = new ProductPageViewModel(); 

    productPageViewModel.ProductPageCriteria = BuildProductPageCriteriaViewModel(); 
    productPageViewModel.Products = GetProducts(productPageViewModel.ProductPageCriteria); 

    return View(productPageViewModel); 
} 

[HttpPost] 
public ActionResult Index(ProductPageViewModel productPageViewModel, FormCollection formCollection) 
{ 
    // productPageViewModel is not populated with posted values of ProductPageCriteria.CategoryID, ProductPageCriteria.DepartmentID and ProductPageCriteria.PageSize 
    // formCollection has correct values 
    // Calling UpdateModel(productPageViewModel); has no affect - makes sense, the framework has already called it 
    // Calling UpdateModel(productPageViewModel.ProductPageCriteria); populates the values. 
    // The renderd form has names like CategoryID, DepartmentID unlike ProductPageCriteria.CategoryID, ProductPageCriteria.DepartmentID 
    //  if the top model was passed to all partial views also. 

    return View(productPageViewModel); 
} 

模型

public class ProductPageCriteriaViewModel 
{ 
    public const int DefaultPageSize = 15; 

    public ProductPageCriteriaViewModel() 
    { 
     Categories = new List<Category>(); 
     Departments = new List<Department>(); 

     PageSize = DefaultPageSize; 
    } 

    [Display(Name = "Category")] 
    public int? CategoryID { get; set; } 
    [Display(Name = "Department")] 
    public int DepartmentID { get; set; } 
    [Display(Name = "Page Size")] 
    public int? PageSize { get; set; } 

    public List<Category> Categories { get; set; } 
    public List<Department> Departments { get; set; } 
} 

public class ProductPageViewModel 
{ 
    public ProductPageViewModel() 
    { 
     ProductPageCriteria = new ProductPageCriteriaViewModel(); 
     Products = new List<Product>(); 
    } 

    public ProductPageCriteriaViewModel ProductPageCriteria { get; set; } 
    public List<Product> Products { get; set; } 
} 

public class Product 
{ 
    public int ProductID { get; set; } 
    public string ProductName { get; set; } 

    public Category Category { get; set; } 
    public Department Department { get; set; } 
} 

public class Category 
{ 
    public int CategoryID { get; set; } 
    public string CategoryName { get; set; } 
} 

public class Department 
{ 
    public int DepartmentID { get; set; } 
    public string DepartmentName { get; set; } 
} 

查看Index.cshtml

@using (Html.BeginForm()) { 
    @Html.ValidationSummary(true) 

    @Html.Partial("_ProductCriteria", Model.ProductPageCriteria) 

    @Html.Partial("_ProductList", Model.Products) 
} 

管窥_ProductCriteria.cshtml

@model Mvc3Application4.Models.ProductPageCriteriaViewModel 

<fieldset> 
    <legend>Criteria</legend> 

    <div class="editor-label"> 
     @Html.LabelFor(model => model.CategoryID) 
    </div> 
    <div class="editor-field"> 
     @Html.DropDownListFor(model => model.CategoryID, new SelectList(Model.Categories, "CategoryID", "CategoryName", Model.CategoryID), "--- All ---") 
     @Html.ValidationMessageFor(model => model.CategoryID) 
    </div> 

    <div class="editor-label"> 
     @Html.LabelFor(model => model.DepartmentID) 
    </div> 
    <div class="editor-field"> 
     @Html.DropDownListFor(model => model.DepartmentID, new SelectList(Model.Departments, "DepartmentID", "DepartmentName", Model.DepartmentID), "--- All ---") 
     @Html.ValidationMessageFor(model => model.DepartmentID) 
    </div> 

    <div class="editor-label"> 
     @Html.LabelFor(model => model.PageSize) 
    </div> 
    <div class="editor-field"> 
     @Html.DropDownListFor(model => model.PageSize, new SelectList(new List<int> {10, 15, 20, 25, 50, 100}.Select(n => new {Value = n, Text = n}), "Value", "Text", Model.PageSize), "--- All ---") 
     @Html.ValidationMessageFor(model => model.PageSize) 
    </div> 

    <p> 
     <input type="submit" value="Search" /> 
    </p> 
</fieldset> 

局部视图_ProductList.cshtml

@model IEnumerable<Mvc3Application4.Models.Product> 

<p> 
    @Html.ActionLink("Create New", "Create") 
</p> 
<table> 
    <tr> 
     <th></th> 
     <th> 
      ProductName 
     </th> 
    </tr> 

@foreach (var item in Model) { 
    <tr> 
     <td> 
      @Html.ActionLink("Edit", "Edit", new { id=item.ProductID }) | 
      @Html.ActionLink("Details", "Details", new { id=item.ProductID }) | 
      @Html.ActionLink("Delete", "Delete", new { id=item.ProductID }) 
     </td> 
     <td> 
      @item.ProductName 
     </td> 
    </tr> 
} 

</table> 
+0

如果我添加一个调用UpdateModel(productPageViewModel.ProductPageCriteria);子模型(ProductPageCriteria)被更新。表单输入在名称中没有任何装饰,所以它使得敏捷为什么它以这种方式工作。这是正确的方式吗?任何其他方式? – 2011-04-15 18:39:29

+0

你能告诉我为什么你有FormCollection作为你的第二个参数吗? – sarvesh 2011-04-15 20:27:28

+0

对于这个问题,可以忽略。它的存在或不存在没有任何区别。我添加它来验证所有提交的值(在fiddler中验证)确实显示该方法。 – 2011-04-15 20:29:41

回答

3

这是我的头和未经考验的顶部,但我相信,如果你通过父模型(ProductPageViewModel)的产品标准局部视图,改变局部视图继承此模型,并更改要使用的控件model => model.ProductPageCriteria.CategoryID而不是model => model.CategoryID,它应该保持命名,以便UpdateModel可以使用发布的值匹配字段。

对不起,对于极端的磨合句,如果这是不正确的,我相信我会很快赢得我的Peer Pressure徽章。 :) 希望这可以帮助。

+0

是的,工作正常。事实上,我早先就是这么做的。为了重构,我想让视图依赖于较小的模型,即仅使用他们需要的视图。例如,在这种情况下,_ProductCriteria.cshtml不需要比ProductPageCriteriaViewModel多。我也可以让它工作,只是我必须为每个子模型调用UpdateModel。我想知道这是否正确,这也是其他人处理它的方式。 – 2011-04-16 04:20:00

+0

我不是MVC最佳实践方面的专家,但我相信在数据从控制器过去之前,主视图会将部分视图渲染到页面中。由于主视图继承传递子视图模型的父视图模型将与传递父视图模型相同,除了为其生成的名称外。我可能完全错误,但这是我对这个过程的看法。尽管我有兴趣听到别人的回应。 – Dusty 2011-04-16 16:03:54