2010-02-25 50 views
8

Tôi đang cố gắng triển khai Edit ViewModel cho thực thể Linq2SQL của tôi được gọi là Product. Nó có một khóa ngoại được liên kết với một danh sách các thương hiệu.ViewModel với SelectList ràng buộc trong ASP.NET MVC2

Hiện nay tôi đang Populating danh sách thương hiệu qua ViewData và sử dụng DropDownListFor, như sau:

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

Bây giờ tôi muốn Refactor xem để sử dụng một ViewModel gõ mạnh và Html.EditorForModel():

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

    <fieldset> 
     <legend>Fields</legend> 

     <%=Html.EditorForModel() %> 

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

<% } %> 

Trong Sửa ViewModel của tôi, tôi đã điều sau đây:

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; 
    } 
} 

các con xe đẩy được thiết lập như vậy:

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); 
} 

ProductId, Tên và mô tả hiển thị chính xác trong chế độ xem được tạo nhưng danh sách chọn không hiển thị. Danh sách thương hiệu chắc chắn chứa dữ liệu.

Nếu tôi làm như sau trong quan điểm của tôi, SelectList có thể nhìn thấy:

<% 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> 

<% } %> 

Tôi đang làm gì sai? EditorForModel() không hỗ trợ chung cho SelectList? Tôi có thiếu một số loại DataAnnotation không?

Tôi dường như không tìm thấy bất kỳ ví dụ nào về việc sử dụng SelectList trong ViewModels có thể trợ giúp. Tôi thực sự bối rối. This answer dường như rất gần nhưng không giúp được gì.

+0

Có vẻ như phiên bản tiếp theo có thể hỗ trợ những gì tôi đang tìm kiếm: http://aspalliance.com/1687_ASPNET_MVC_Preview_3_Release.3 – Junto

Trả lời

4

phe đảng,

phương pháp Html.EditorForModel() là không đủ thông minh để phù hợp với BrandId danh sách lựa chọn Brands.

Trước tiên, bạn không thể sử dụng phương pháp tắt EditorForModel().
Bạn phải tạo mẫu HTML của riêng mình như thế này.

<% 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> 
<% } %> 



Thứ hai, bạn cần phải thay đổi phương thức hành động của bạn.

[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); 
} 



Thứ ba, bạn cần cập nhật lớp EditProductViewModel của bạn.

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; 
    } 
} 

Bởi bây giờ, bạn có lẽ nói: Dude, nơi là [ProductID] tài sản của tôi "
ngắn trả lời:?. Bạn không cần nó

HTML render! theo quan điểm của bạn đã trỏ đến phương thức hành động "Chỉnh sửa" với "ProductId" thích hợp như được hiển thị bên dưới.

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

Đây là phương thức hành động HTTP POST của bạn và nó chấp nhận 2 tham số.
"id" xuất phát từ thuộc tính hành động của < biểu mẫu >.

[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 rất hữu ích.
Các thuộc tính đó được sử dụng cho mẫu PRG (Đăng chuyển hướng).

Đọc này Sử dụng mẫu PRG để sửa đổi dữ liệu trong bài đăng trên blog này bằng Kazi Manzur Rashid.
http://weblogs.asp.net/rashid/archive/2009/04/01/asp-net-mvc-best-practices-part-1.aspx




Okay, mã dữ liệu ràng buộc này không phải là cách yêu thích của tôi làm việc.

TryUpdateModel<Product>(p); 

cách ưa thích của tôi để làm việc đó là phải có một riênginterface cho dữ liệu tinh khiết ràng buộc.

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 
{ 
} 

Và đây là cách tôi sẽ cập nhật mã ràng buộc dữ liệu của mình.

TryUpdateModel<IProductModel>(p); 

Điều này giúp tôi dễ dàng kết nối dữ liệu với các đối tượng mô hình của mình từ dữ liệu đăng lại. Ngoài ra, nó làm cho nó an toàn hơn vì bạn chỉ ràng buộc dữ liệu mà bạn muốn ràng buộc. Không hơn không kém.

Hãy cho tôi biết nếu bạn có bất kỳ câu hỏi nào.

+0

Cảm ơn Stun. Câu trả lời tốt nhất cho đến nay. Tóm lại, EdutorForModel() không đủ thông minh và tôi vẫn phải sử dụng chuỗi ViewData và chuỗi ma thuật để có được danh sách SelectList. Hướng dẫn rất hữu ích. Cảm ơn bạn. – Junto

0

Bạn nên tạo tra cứu đó vào ViewModel của mình. Sau đó, tạo một đối tượng Builder để xây dựng ViewModel và điền vào tra cứu đó.

Sau khi tất cả, đó là những gì ViewModel của bạn là: để cung cấp một mô hình cụ thể cho chế độ xem của bạn.

1

Thuộc tính mới DropDownList cho thuộc tính của bạn BrandId có thể hữu ích. Hãy xem bài viết Extending ASP.NET MVC 2 Templates. Nhưng cách tiếp cận này sử dụng ViewData làm nguồn mục của danh sách lựa chọn.

Các vấn đề liên quan