2012-12-26 62 views
18

Giả sử tôi có một mô hình đơn giản để giải thích mục đích:EditorFor IEnumerable <T> với TEMPLATENAME

public class Category 
{ 
    ... 
    public IEnumerable<Product> Products { get; set; } 
} 

Xem:

@model Category 
... 
<ul> 
    @Html.EditorFor(m => m.Products) 
</ul> 

EditorTemplate:

@model Product 
... 
<li> 
    @Html.EditorFor(m => m.Name) 
</li> 

Lưu ý rằng tôi không phải xác định EditorTemplate cho IEnumerable<Product>, tôi chỉ có thể tạo nó choMô hìnhvà khung MVC đủ thông minh để sử dụng mẫu của riêng nó cho IEnumerable. Nó lặp qua bộ sưu tập của tôi và gọi cho EditorTemplate của tôi.

Các html đầu ra sẽ là một cái gì đó như thế này

... 
<li> 
    <input id="Products_i_Name" name="Products[i].Name" type="text" value="SomeName"> 
</li> 

mà tôi có thể gửi đến bộ điều khiển của tôi sau khi tất cả.

Nhưng tại sao MVC không thực hiện thủ thuật khi tôi xác định EditorTemplate với tên mẫu?

@Html.EditorFor(m => m.Products, "ProductTemplate") 

Trong trường hợp đó tôi phải thay đổi loại tài sản để IList<Product>, lặp thông qua bộ sưu tập của bản thân mình và gọi EditorTemplate

@for (int i = 0; i < Model.Products.Count; i++) 
{ 
    @Html.EditorFor(m => m.Products[i], "ProductTemplate") 
} 

mà dường như loại workaround bẩn với tôi. Có giải pháp nào khác, sạch hơn để làm điều này không?

+0

thể trùng lặp của [Đúng, cách thành ngữ để sử dụng các mẫu biên tập tùy chỉnh với các mô hình IEnumerable trong ASP.NET MVC] (http://stackoverflow.com/questions/25333332/correct-idiomatic-way-to-use -custom-editor-templates-with-ienumerable-models-in) – GSerg

+0

Không chắc chắn làm thế nào tôi bỏ qua câu hỏi này khi tìm kiếm trước khi tạo [câu hỏi đó] (http://stackoverflow.com/questions/25333332/correct-idiomatic-way- để sử dụng-tùy chỉnh-editor-templates-với-ienumerable-mô hình-in) của tôi. Theo đó, câu hỏi của tôi phải được đóng lại như một bản sao của câu hỏi này, nhưng tôi tin rằng nó nên là một cách khác vì có cách giải quyết khác. – GSerg

+2

@GSerg, cảm ơn bạn đã chia sẻ câu trả lời của mình. Tôi không thể nói rằng tôi thích bất kỳ giải pháp được đề xuất nào tốt hơn một vòng lặp 'for' đơn giản thông qua bộ sưu tập. Xin lỗi vì đã không rõ ràng với câu hỏi của tôi, nhưng tôi đã không tìm cách giải quyết vấn đề này, nhưng đối với sạch sẽ và (tôi đã hy vọng) là cách duy nhất để thực hiện điều này. Đó là lý do tại sao tôi không thể nói câu trả lời cho câu hỏi của bạn đã giải quyết được vấn đề của tôi, mặc dù câu hỏi của họ rất giống nhau. – Zabavsky

Trả lời

13

Có giải pháp nào khác, sạch hơn để thực hiện việc này không?

Câu trả lời đơn giản là không, nó rất tệ, tôi hoàn toàn đồng ý với bạn, nhưng đó là cách các nhà thiết kế khung công tác quyết định triển khai tính năng này.

Vì vậy, điều tôi làm là gắn bó với các quy ước. Vì tôi có các mô hình chế độ xem cụ thể cho mỗi chế độ xem và partials, không phải là một việc lớn để có mẫu trình chỉnh sửa tương ứng, được đặt tên giống như kiểu bộ sưu tập.

+0

Điều đó tôi sợ.Vấn đề là tôi phải sử dụng cùng ViewModel cho một số Views liên quan và nó phụ thuộc vào View như thế nào để hiển thị ViewModel này. Nhưng cảm ơn, Darin, cho câu trả lời, tôi đánh giá cao nó. – Zabavsky

15

Hiện tại, tôi chỉ nợ Darin 9999 bia.

public static MvcHtmlString EditorForMany<TModel, TValue>(this HtmlHelper<TModel> html, Expression<Func<TModel, IEnumerable<TValue>>> expression, string templateName = null) where TModel : class 
    { 
     StringBuilder sb = new StringBuilder(); 

     // Get the items from ViewData 
     var items = expression.Compile()(html.ViewData.Model); 
     var fieldName = ExpressionHelper.GetExpressionText(expression); 
     var htmlFieldPrefix = html.ViewContext.ViewData.TemplateInfo.HtmlFieldPrefix; 
     var fullHtmlFieldPrefix = String.IsNullOrEmpty(htmlFieldPrefix) ? fieldName : String.Format("{0}.{1}", htmlFieldPrefix, fieldName); 
     int index = 0; 

     foreach (TValue item in items) 
     { 
      // Much gratitude to Matt Hidinger for getting the singleItemExpression. 
      // Current html.DisplayFor() throws exception if the expression is anything that isn't a "MemberAccessExpression" 
      // So we have to trick it and place the item into a dummy wrapper and access the item through a Property 
      var dummy = new { Item = item }; 

      // Get the actual item by accessing the "Item" property from our dummy class 
      var memberExpression = Expression.MakeMemberAccess(Expression.Constant(dummy), dummy.GetType().GetProperty("Item")); 

      // Create a lambda expression passing the MemberExpression to access the "Item" property and the expression params 
      var singleItemExpression = Expression.Lambda<Func<TModel, TValue>>(memberExpression, 
                       expression.Parameters); 

      // Now when the form collection is submitted, the default model binder will be able to bind it exactly as it was. 
      var itemFieldName = String.Format("{0}[{1}]", fullHtmlFieldPrefix, index++); 
      string singleItemHtml = html.EditorFor(singleItemExpression, templateName, itemFieldName).ToString(); 
      sb.AppendFormat(singleItemHtml); 
     } 

     return new MvcHtmlString(sb.ToString()); 
    } 
+1

Bạn có thể thêm một ví dụ về cách bạn sẽ sử dụng tính năng này không? –

+0

Tôi nhận được một ngoại lệ tham chiếu null khi truy xuất html.ViewData.Model. Bất kì manh mối nào? –

+1

'@ Html.EditorForMany (x => Model.Products)' –

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