2012-10-09 64 views
7

在MVC中,你可以當你想渲染類型的屬性IEnumerable<T>你可以簡單地做一個例如編輯爲T創建編輯模板,然後如何創建使用UIHint的EditorTemplate與IEnumerable的類型的屬性<T>

Html.EditorFor(m => m.MyListOfT) 

這樣做的好處是,名稱會自動由框架用於輸入回發模型很好地結合所有的作品時創建,然後。

我的問題是:當你有多種類型的編輯器模板時,你如何做到以上幾點?

我試過使用UIHint(),但它似乎只允許您指定對列表的UIHint,而不是列表中的每個項目。這意味着你必須使用foreach()循環爲列表創建一個EditorTemplate,然後你錯過了很好的自動命名和模型綁定。

我在這裏錯過了什麼?

該模型是例如

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

理想我想要做的事,如:

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

,並有自動應用到列表中的所有元素,所以我可以只呈現:

Html.EditorFor(m => m.SomeProperty) 

回答

10

我在這裏錯過了什麼?

什麼都沒有。不幸的是,這是如此。如果您在調用Html.EditorFor時指定模板名稱或使用UIHint,則將爲該列表調用模板,而不是爲每個元素調用該模板。

這是說你當然可以寫一個自定義擴展方法,將實現這樣的功能:

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

,可以在其上飾有UIHint屬性類型的集合視圖模型屬性操作:

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

,並在您的視圖:

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

和y我們~/Views/Shared/EditorTemplates/SomeTypeTemplate.cshtml現在可以輸入到一個ItemViewModel

@model ItemViewModel 
... 

你不再需要它,你會簡單地循環和調用實際的模板中介顯示模板 - 這將是一個真正的浪費。

+0

優秀:-)謝謝Darin – magritte

2

創建2 EditorTemplates。一個處理IEnumerable,並且此模板循環爲枚舉中的每個項目創建一個

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

1

雖然@ Darin的答案是完美的,但由於某些原因,我仍未找到ModelMetaData中的TemplateHint始終爲空。至於解決方案,我還創建了@ Darin代碼的一個重載,以接受模板名稱參數並呈現View而不是檢查ModelMetaData中的TemplateHint。對不起,作爲回答發佈它,因爲我沒有權限發佈爲評論。謝謝Darin :)

相關問題