我可以专门为 IEnumerable 属性创建一个 HtmlHelper 吗?
Can I create a HtmlHelper specifically for IEnumerable properties?
我想创建一个可用于 IEnumerable 属性的 HtmlHelper。
目的是这样使用它:
@Html.DisplayForEnumerable(m => m.EnumerableItemsProperty, "ViewTemplateName");
如果可能的话,我想使用 m => m.Items
lambda 语法(而不是通过 Model.Items
)。
这是我迄今为止的最大努力。但我不确定如何从表达式参数中获取 items
变量。
我怀疑我可能必须使用 IEnumerable<TValue>
之类的东西作为表达式的 return 类型,但我对泛型很陌生,我不知道如何实现它。
public static MvcHtmlString DisplayForEnumerable<TModel>(this HtmlHelper<TModel> html, Expression<Func<TModel, IEnumerable>> expression, string templateName, object additonalViewData = null)
{
var sb = new StringBuilder();
// how to get items variable?
foreach (var item in items)
{
var item1 = item;
sb.Append(html.DisplayFor(m => item1, templateName, additonalViewData));
}
return MvcHtmlString.Create(sb.ToString());
}
更新
澄清一下 - 我采用这种方法是因为我希望能够为同一模型指定不同的模板。如果指定特定模板,则不会发生正常的 DisplayFor()
枚举。
我知道我可以手动枚举,但我宁愿使用这种方法,除非更有知识的人提出其他建议。
你的助手需要
public static MvcHtmlString DisplayForEnumerable<TModel, TProperty>(this HtmlHelper<TModel> helper, Expression<Func<TModel, TProperty>> expression, string templateName, object additionalViewData = null)
{
ModelMetadata metaData = ModelMetadata.FromLambdaExpression(expression, helper.ViewData);
IEnumerable collection = metaData.Model as IEnumerable;
if (collection == null)
{
return helper.DisplayFor(expression, templateName, additionalViewData );
}
StringBuilder html = new StringBuilder();
foreach (var item in collection)
{
html.Append(helper.DisplayFor(m => item, templateName, additionalViewData).ToString());
}
return MvcHtmlString.Create(html.ToString());
}
请注意,代码允许您传递单个 T
或 IEnumerable<T>
(尽管方法名称现在没有实际意义)。如果你想将它限制为只有 IEnumerable<T>
你可以抛出一个 InvalidCastException
if collection == null
请注意,如果您想为集合生成表单控件(例如 EditorForEnumerable()
方法),此方法将不起作用,因为所需的集合索引器不会添加到生成 name
属性。更好的方法是使用内置的 DisplayFor()
和 EditorFor()
方法,它们将为 T
和 IEnemerable<T>
生成正确的 html
假设您有一个 Person.cs
class,在 /Views/Shared/DisplayTemplates/Person.cshtml
中创建一个局部视图(注意文件名必须与 class 的名称匹配)并且在视图中只需使用
@Html.DisplayFor(m => m.yourCollectionProperty)
您还可以为每个控制器创建特定的显示和编辑器模板,例如 /Views/yourControllerName/DisplayTemplates/Person.cshtml
。这允许您在 /Persons/Index
中使用一个模板,在 /Organisation/Details/1
中使用另一个模板,这可能会显示与 Organisation
关联的 Person
列表
最后,如果您确实需要在同一个控制器中为 Person
使用 2 个不同的模板,您可以使用视图模型,例如 class PersonVM
和 class AssociatedPersonVM
并创建一个 EditorTemplate
每个
我想创建一个可用于 IEnumerable 属性的 HtmlHelper。
目的是这样使用它:
@Html.DisplayForEnumerable(m => m.EnumerableItemsProperty, "ViewTemplateName");
如果可能的话,我想使用 m => m.Items
lambda 语法(而不是通过 Model.Items
)。
这是我迄今为止的最大努力。但我不确定如何从表达式参数中获取 items
变量。
我怀疑我可能必须使用 IEnumerable<TValue>
之类的东西作为表达式的 return 类型,但我对泛型很陌生,我不知道如何实现它。
public static MvcHtmlString DisplayForEnumerable<TModel>(this HtmlHelper<TModel> html, Expression<Func<TModel, IEnumerable>> expression, string templateName, object additonalViewData = null)
{
var sb = new StringBuilder();
// how to get items variable?
foreach (var item in items)
{
var item1 = item;
sb.Append(html.DisplayFor(m => item1, templateName, additonalViewData));
}
return MvcHtmlString.Create(sb.ToString());
}
更新
澄清一下 - 我采用这种方法是因为我希望能够为同一模型指定不同的模板。如果指定特定模板,则不会发生正常的 DisplayFor()
枚举。
我知道我可以手动枚举,但我宁愿使用这种方法,除非更有知识的人提出其他建议。
你的助手需要
public static MvcHtmlString DisplayForEnumerable<TModel, TProperty>(this HtmlHelper<TModel> helper, Expression<Func<TModel, TProperty>> expression, string templateName, object additionalViewData = null)
{
ModelMetadata metaData = ModelMetadata.FromLambdaExpression(expression, helper.ViewData);
IEnumerable collection = metaData.Model as IEnumerable;
if (collection == null)
{
return helper.DisplayFor(expression, templateName, additionalViewData );
}
StringBuilder html = new StringBuilder();
foreach (var item in collection)
{
html.Append(helper.DisplayFor(m => item, templateName, additionalViewData).ToString());
}
return MvcHtmlString.Create(html.ToString());
}
请注意,代码允许您传递单个 T
或 IEnumerable<T>
(尽管方法名称现在没有实际意义)。如果你想将它限制为只有 IEnumerable<T>
你可以抛出一个 InvalidCastException
if collection == null
请注意,如果您想为集合生成表单控件(例如 EditorForEnumerable()
方法),此方法将不起作用,因为所需的集合索引器不会添加到生成 name
属性。更好的方法是使用内置的 DisplayFor()
和 EditorFor()
方法,它们将为 T
和 IEnemerable<T>
假设您有一个 Person.cs
class,在 /Views/Shared/DisplayTemplates/Person.cshtml
中创建一个局部视图(注意文件名必须与 class 的名称匹配)并且在视图中只需使用
@Html.DisplayFor(m => m.yourCollectionProperty)
您还可以为每个控制器创建特定的显示和编辑器模板,例如 /Views/yourControllerName/DisplayTemplates/Person.cshtml
。这允许您在 /Persons/Index
中使用一个模板,在 /Organisation/Details/1
中使用另一个模板,这可能会显示与 Organisation
Person
列表
最后,如果您确实需要在同一个控制器中为 Person
使用 2 个不同的模板,您可以使用视图模型,例如 class PersonVM
和 class AssociatedPersonVM
并创建一个 EditorTemplate
每个