巩固Jamiec和马丁展位的答案。我创建了以下扩展方法。它将IEnumerable作为第一个参数,然后使用两个代表来呈现文本。在Razor Views中我们可以通过模板化代表两个这些参数。总之这意味着你可以在模板中输入。因此,这里的扩展方法,你可以怎么称呼它:
public static HelperResult Each<TItem>(this IEnumerable<TItem> items,
Func<TItem, HelperResult> eachTemplate,
Func<dynamic, HelperResult> other)
{
return new HelperResult(writer =>
{
foreach (var item in items)
{
var result = eachTemplate(item);
result.WriteTo(writer);
}
if (!items.Any())
{
var otherResult = other(new ExpandoObject());
// var otherResult = other(default(TItem));
otherResult.WriteTo(writer);
}
});
}
而且在剃刀观点:
@Model.Users.Each(
@<li>@item.Name</li>,
@<li>
<b>No Items</b>
</li>
)
所有的一切,很干净。
UPDATE实施评论中提出的建议。此扩展方法需要一个参数来循环集合中的项目并返回一个自定义的HelperResult。在那个帮助结果中,可以调用Else
方法在没有找到任何项目的情况下传入模板委托。
public static class HtmlHelpers
{
public static ElseHelperResult<TItem> Each<TItem>(this IEnumerable<TItem> items,
Func<TItem, HelperResult> eachTemplate)
{
return ElseHelperResult<TItem>.Create(items, eachTemplate);
}
}
public class ElseHelperResult<T> : HelperResult
{
private class Data
{
public IEnumerable<T> Items { get; set; }
public Func<T, HelperResult> EachTemplate { get; set; }
public Func<dynamic, HelperResult> ElseTemplate { get; set; }
public Data(IEnumerable<T> items, Func<T, HelperResult> eachTemplate)
{
Items = items;
EachTemplate = eachTemplate;
}
public void Render(TextWriter writer)
{
foreach (var item in Items)
{
var result = EachTemplate(item);
result.WriteTo(writer);
}
if (!Items.Any() && ElseTemplate != null)
{
var otherResult = ElseTemplate(new ExpandoObject());
// var otherResult = other(default(TItem));
otherResult.WriteTo(writer);
}
}
}
public ElseHelperResult<T> Else(Func<dynamic, HelperResult> elseTemplate)
{
RenderingData.ElseTemplate = elseTemplate;
return this;
}
public static ElseHelperResult<T> Create(IEnumerable<T> items, Func<T, HelperResult> eachTemplate)
{
var data = new Data(items, eachTemplate);
return new ElseHelperResult<T>(data);
}
private ElseHelperResult(Data data)
: base(data.Render)
{
RenderingData = data;
}
private Data RenderingData { get; set; }
}
这可以被称为如下:
@(Model.Users
.Each(@<li>@item.Name</li>)
.Else(
@<li>
<b>No Users</b>
</li>
)
)
逗号几乎不可见。 :P –
我同意,但我们没有办法绕过这个方法,我们可以吗? :) – Thomas
如果你为else子句使用命名参数,它可能更具可读性,你可以使它成为可选 –