2012-10-09 15 views
7

Trong MVC bạn có thể tạo một mẫu biên tập viên cho T và sau đó khi bạn muốn làm biên tập viên cho một loại tài sản của IEnumerable<T> bạn chỉ có thể làm ví dụLàm thế nào để tạo ra một EditorTemplate sử dụng UIHint với một loại tài sản của IEnumerable <T>

Html.EditorFor(m => m.MyListOfT) 

Vẻ đẹp của tên này được tạo tự động bởi khuôn khổ cho đầu vào và sau đó đăng lại mô hình ràng buộc tất cả hoạt động tốt.

Câu hỏi của tôi là: làm cách nào để thực hiện điều này khi bạn có nhiều loại mẫu trình chỉnh sửa?

Tôi đã thử sử dụng UIHint(), tuy nhiên, dường như nó chỉ cho phép bạn chỉ định UIHint đối với danh sách, chứ không phải từng mục trong danh sách. Điều này có nghĩa là bạn phải tạo một EditorTemplate cho danh sách, với một vòng lặp foreach(), và sau đó bạn bỏ lỡ việc tự động đặt tên và ràng buộc mô hình tốt đẹp.

Tôi thiếu gì ở đây?

Mô hình là ví dụ:

public class MyViewModel 
{ 
    public IEnumerable<SomeType> SomeProperty { get; set; } 
} 

Lý tưởng nhất là tôi muốn làm một cái gì đó như:

public class MyViewModel 
{ 
    [UIHint("SomeTypeTemplate")] 
    public IEnumerable<SomeType> SomeProperty { get; set; } 
} 

và có tự động áp dụng đối với tất cả các yếu tố trong danh sách vì vậy tôi có thể làm cho chỉ với:

Html.EditorFor(m => m.SomeProperty) 

Trả lời

10

Tôi thiếu gì ở đây?

Không có gì. Thật không may đó là cách nó được. Nếu bạn chỉ định tên mẫu khi gọi Html.EditorFor hoặc sử dụng UIHint, mẫu sẽ được gọi cho danh sách chứ không phải cho từng phần tử.

này đang được nói bạn tất nhiên có thể viết một phương pháp mở rộng thông thường mà sẽ đạt được chức năng này:

public static class HtmlExtensions 
{ 
    private class ViewDataContainer: IViewDataContainer 
    { 
     public ViewDataContainer(ViewDataDictionary viewData) 
     { 
      ViewData = viewData; 
     } 

     public ViewDataDictionary ViewData { get; set; } 
    } 

    public static IHtmlString EditorForCollection<TModel, TProperty>(
     this HtmlHelper<TModel> html, 
     Expression<Func<TModel, IList<TProperty>>> expression 
    ) 
    { 
     var metadata = ModelMetadata.FromLambdaExpression(expression, html.ViewData); 
     if (string.IsNullOrEmpty(metadata.TemplateHint)) 
     { 
      return html.EditorFor(expression); 
     } 

     var collection = metadata.Model as IList<TProperty>; 

     var sb = new StringBuilder(); 
     for (int i = 0; i < collection.Count; i++) 
     { 
      var indexExpression = Expression.Constant(i, typeof(int)); 
      var itemGetter = expression.Body.Type.GetProperty("Item", new[] { typeof(int) }).GetGetMethod(); 
      var methodCallExpression = Expression.Call(expression.Body, itemGetter, indexExpression); 
      var itemExpression = Expression.Lambda<Func<TModel, TProperty>>(methodCallExpression, expression.Parameters[0]); 
      var result = html.EditorFor(itemExpression, metadata.TemplateHint).ToHtmlString(); 
      sb.AppendLine(result); 
     } 
     return new HtmlString(sb.ToString()); 
    } 
} 

mà có thể hoạt động trên các thuộc tính xem mô hình của bộ sưu tập kiểu đó được trang trí với các thuộc tính UIHint:

public class MyViewModel 
{ 
    [UIHint("SomeTypeTemplate")] 
    public IList<ItemViewModel> Items { get; set; } 
} 

và theo quan điểm của bạn:

@model MyViewModel 
@Html.EditorForCollection(x => x.Items) 

và y ~/Views/Shared/EditorTemplates/SomeTypeTemplate.cshtml chúng tôi bây giờ có thể được gõ vào một đơn ItemViewModel:

@model ItemViewModel 
... 

Bạn không còn cần một mẫu màn hình trung gian trong đó bạn sẽ chỉ đơn giản được lặp và kêu gọi các mẫu thực tế - đó sẽ là một sự lãng phí thực.

+0

Tuyệt vời :-) cảm ơn Darin – magritte

2

Bạn tạo 2 EditorTemplates. Một xử lý IEnumerable và mẫu này lặp lại để tạo ra một

Html.EditorFor(m => m.SomeProperty, "SomeIndividualTemplate") 

cho mỗi mục trong liệt kê.

1

Mặc dù câu trả lời của @ Darin là hoàn hảo, vì một số lý do mà tôi chưa tìm thấy TemplateHint từ ModelMetaData luôn là rỗng. Như giải pháp tôi đã tạo thêm một quá tải mã @ Darin để chấp nhận tham số tên mẫu và hiển thị Chế độ xem thay vì kiểm tra TemplateHint trong ModelMetaData. Xin lỗi để gửi nó như là câu trả lời như tôi không có đặc quyền để gửi bình luận. Cảm ơn Darin :)

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