2010-02-25 32 views
8

我想爲我的稱爲Product的Linq2SQL實體實現一個Edit ViewModel。它有一個外鍵鏈接到品牌列表。在ASP.NET MVC2中使用SelectList綁定的ViewModel

目前我通過填充ViewData的品牌列表,並使用DropDownListFor,即:

<div class="editor-field"> 
    <%= Html.DropDownListFor(model => model.BrandId, (SelectList)ViewData["Brands"])%> 
    <%= Html.ValidationMessageFor(model => model.BrandId) %> 
</div> 

現在我想重構視圖中使用強類型的視圖模型和Html.EditorForModel():

<% using (Html.BeginForm()) {%> 
    <%= Html.ValidationSummary(true) %> 

    <fieldset> 
     <legend>Fields</legend> 

     <%=Html.EditorForModel() %> 

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

<% } %> 

在我的編輯視圖模型,我有以下幾點:

public class EditProductViewModel 
{ 
    [HiddenInput] 
    public int ProductId { get; set; } 

    [Required()] 
    [StringLength(200)] 
    public string Name { get; set; } 

    [Required()] 
    [DataType(DataType.Html)] 
    public string Description { get; set; } 

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

    public int BrandId { get; set; } 

    public EditProductViewModel(Product product, IEnumerable<SelectListItem> brands) 
    { 
     this.ProductId = product.ProductId; 
     this.Name = product.Name; 
     this.Description = product.Description; 
     this.Brands = brands; 
     this.BrandId = product.BrandId; 
    } 
} 

的CON troller是設置像這樣:

public ActionResult Edit(int id) 
{ 
    BrandRepository br = new BrandRepository(); 

    Product p = _ProductRepository.Get(id); 
    IEnumerable<SelectListItem> brands = br.GetAll().ToList().ToSelectListItems(p.BrandId); 

    EditProductViewModel model = new EditProductViewModel(p, brands); 

    return View("Edit", model); 
} 

產品ID,名稱和描述在正確生成的視圖顯示,但是選擇列表沒有。品牌列表中包含數據。

如果我這樣做,我認爲,選擇列表的可見:

<% using (Html.BeginForm()) {%> 
    <%= Html.ValidationSummary(true) %> 

    <fieldset> 
     <legend>Fields</legend> 

     <%=Html.EditorForModel() %> 

     <div class="editor-label"> 
      <%= Html.LabelFor(model => model.BrandId) %> 
     </div> 
     <div class="editor-field"> 
      <%= Html.DropDownListFor(model => model.BrandId, Model.Brands)%> 
      <%= Html.ValidationMessageFor(model => model.BrandId) %> 
     </div> 
     <p> 
      <input type="submit" value="Save" /> 
     </p> 
    </fieldset> 

<% } %> 

我在做什麼錯? EditorForModel()不一般支持SelectList嗎?我是否缺少某種DataAnnotation?

我似乎無法找到ViewModels中的SelectList用法的任何示例幫助。我真的很難過。 This answer似乎接近,但沒有幫助。

+0

看起來像下一個版本可能支持我在找什麼:http://aspalliance.com/1687_ASPNET_MVC_Preview_3_Release.3 – Junto 2010-05-06 06:56:27

回答

4

幫派,

Html.EditorForModel()方法是不夠聰明與Brands選擇列表匹配BrandId

首先,您不能使用快捷方式EditorForModel()方法。
你必須像這樣創建你自己的HTML模板。

<% using (Html.BeginForm()) { %> 

    <div style="display:none"><%= Html.AntiForgeryToken() %></div> 

    <table> 
     <tr> 
      <td><%= Html.LabelFor(m => m.Name) %></td> 
      <td><%= Html.EditorFor(m => m.Name) %></td> 
     </tr> 

     <tr> 
      <td><%= Html.LabelFor(m => m.Description) %></td> 
      <td><%= Html.EditorFor(m => m.Description) %></td> 
     </tr> 

     <tr> 
      <td><%= Html.LabelFor(m => m.BrandId) %></td> 
      <td><%= Html.EditorFor(m => m.BrandId) %></td> 
     </tr> 
    </table> 
<% } %> 



其次,你需要改變你的操作方法。

[ImportModelStateFromTempData] 
public ActionResult Edit(int id) 
{ 
    BrandRepository br = new BrandRepository(); 

    Product p = _ProductRepository.Get(id); 
    ViewData["BrandId"] = br.GetAll().ToList().ToSelectListItems(p.BrandId); 

    EditProductViewModel model = new EditProductViewModel(p); 

    return View("Edit", model); 
} 



第三,你需要更新你的EditProductViewModel類。

public class EditProductViewModel 
{ 
    [Required] 
    [StringLength(200)] 
    public string Name { get; set; } 

    [Required()] 
    [DataType(DataType.Html)] 
    public string Description { get; set; } 

    [Required] // this foreign key *should* be required 
    public int BrandId { get; set; } 

    public EditProductViewModel(Product product) 
    { 
     this.Name = product.Name; 
     this.Description = product.Description; 
     this.BrandId = product.BrandId; 
    } 
} 

現在,你可能會說:老兄,哪裏是我的的[ProductID]財產「
簡答題:你不需要它

呈現的HTML!根據您的觀點,已經指出「編輯」操作方法具有適當的「ProductId」,如下所示:

<form action="/Product/Edit/123" method="post"> 
    ... 
</form> 

這是您的HTTP POST操作方法,它接受2個參數。
「id」來自<表格>標籤的操作屬性。

[HttpPost, ValidateAntiForgeryToken, ExportModelStateToTempData] 
public ActionResult Edit(int id, EditProductViewModel model) 
{ 
    Product p = _ProductRepository.Get(id); 

    // make sure the product exists 
    // otherwise **redirect** to [NotFound] view because this is a HTTP POST method 
    if (p == null) 
     return RedirectToAction("NotFound", new { id = id }); 

    if (ModelState.IsValid) 
    { 
     TryUpdateModel<Product>(p); 
     _ProductRepository.UpdateProduct(p); 
    } 

    return RedirectToAction("Edit", new { id = id }); 
} 

ExportModelStateToTempDataImportModelStateFromTempData是非常有用的。
這些屬性用於PRG(Post重定向獲取)模式。

通過卡子門祖爾拉希德閱讀本博客帖子這個使用PRG模式的數據修改部分。
http://weblogs.asp.net/rashid/archive/2009/04/01/asp-net-mvc-best-practices-part-1.aspx




好吧,這個數據綁定代碼不是我喜歡的做事方式。

TryUpdateModel<Product>(p); 

我最喜歡做的方式是有一個獨立的interface純數據綁定。

public interface IProductModel 
{ 
    public string Name {get; set;} 
    public string Description {get; set;} 
    public int BrandId {get; set;} 
} 

public partial class Product : IProductModel 
{ 
} 

public partial class EditProductViewModel : IProductModel 
{ 
} 

這就是我將如何更新我的數據綁定代碼。

TryUpdateModel<IProductModel>(p); 

這有什麼幫助,它使我可以簡單地將數據綁定到回發數據中的模型對象。 此外,它使它更安全,因爲您只綁定了要綁定的數據。沒有更多,沒有更多。

讓我知道你是否有任何問題。

+0

謝謝Stun。最好的答案。總之,EdutorForModel()不夠智能,我仍然需要使用ViewData和magic字符串來獲取SelectList。非常有用的演練。謝謝。 – Junto 2010-06-19 11:13:11

0

你應該在你的ViewModel中建立這個查找。然後創建一個構建ViewModel並填充查找的Builder對象。

畢竟,這就是您的ViewModel的用途:專門爲您的視圖提供模型。

1

一個新的屬性DropDownList爲您的財產BrandId可能會有所幫助。看看Extending ASP.NET MVC 2 Templates文章。但是這種方法使用ViewData作爲選擇列表的項目源。

相關問題