鉴于这样的视图模型:
public class ParentViewModel
{
public object ChildViewModel { get; set; }
}
如果我像这样使用Html.LabelFor:
@Html.LabelFor(model => model.ChildViewModel)
我会得到这样的输出:
ChildViewModel
我真正想要的是生成的标签使用应用于对象E.G的DisplayName属性.
[DisplayName("My Custom Label")]
public class ChildViewModel
{
}
输出:
My Custom Label
我知道Html.LabelFor方法接受一个需要一个属性的表达式,它将在该属性上查找DisplayName属性而不是对象本身.
我创建了一个Html帮助器方法来实现我想要的样子:
public static IHtmlString CreateLabel(this HtmlHelper html, Func func)
where TModel : class
{
TagBuilder tb = new TagBuilder("label");
var model = html.ViewData.Model as TModel;
if (model != null)
{
object obj = func(model);
if (obj != null)
{
var attribute = obj.GetType().GetCustomAttributes(
typeof(DisplayNameAttribute), true)
.FirstOrDefault() as DisplayNameAttribute;
if (attribute != null)
{
tb.InnerHtml = attribute.DisplayName;
return MvcHtmlString.Create(tb.ToString());
}
else
{
tb.InnerHtml = obj.ToString();
return MvcHtmlString.Create(tb.ToString());
}
}
}
tb.InnerHtml = html.ViewData.Model.ToString();
return MvcHtmlString.Create(tb.ToString());
}
我的助手不是采用表达式,而是采用Func< TModel,object>它返回我想要检查DisplayName属性的对象.
我遇到的第一个问题是当我试图用剃须刀调用这个方法时:
@Html.CreateLabel(model => model.ChildObject)
我收到以下错误:
The type arguments for method 'CreateLabel(this HtmlHelper,
Func) cannot be inferred from usage. Try specifying
the arguments explicitly.'
所以我调用这样的方法代替:
@{ Html.CreateLabel(model => model.ChildObject); }
但什么都没有渲染.如果我使用调试器逐步执行我的帮助器方法,则会生成label标签,但在呈现页面时不会显示任何内容.
所以我的问题是:
>如何修复此问题以生成我的视图标签?
>我该怎么做才能推断出通用参数?
>有没有办法编写Html助手来做同样的事情,但使用表达式?我没有使用表达式的经验,所以不知道从哪里开始.
更新
我想我会发布最终代码,因为我做了一些小改动.首先,我查看了MVC源代码中的帮助程序,并决定将该方法拆分为三个单独的方法,与提供的示例一致.我还删除了所有TagBuilder的内容,因为我真正需要的是生成要在< legend>< / legend>之间注入的文本.标签.最终代码如下.再次感谢Sylon帮助我解决这个问题.
public static IHtmlString LegendTextFor(this HtmlHelper html, Expression> expression)
{
return LegendTextHelper(html,
ModelMetadata.FromLambdaExpression(expression, html.ViewData),
ExpressionHelper.GetExpressionText(expression),
expression.Compile().Invoke(html.ViewData.Model));
}
private static IHtmlString LegendTextHelper(this HtmlHelper html, ModelMetadata metadata, string htmlFieldName, TObject value)
{
string resolvedLabelText = metadata.DisplayName ?? value.GetDisplayName() ?? metadata.PropertyName ?? htmlFieldName.Split('.').Last();
if (String.IsNullOrEmpty(resolvedLabelText))
return MvcHtmlString.Empty;
return MvcHtmlString.Create(resolvedLabelText);
}
private static string GetDisplayName(this T obj)
{
if (obj != null)
{
var attribute = obj.GetType()
.GetCustomAttributes(typeof(DisplayNameAttribute), false)
.Cast()
.FirstOrDefault();
return attribute != null ? attribute.DisplayName : null;
}
else
{
return null;
}
}