Html.Labelfor使用对象的DisplayName而不是属性
鉴于这样的视图模型:
public class ParentViewModel { public object ChildViewModel { get; set; } }
如果我像这样使用Html.LabelFor
:
@Html.LabelFor(model => model.ChildViewModel)
我会得到这样的输出:
我实际想要的是生成的标签使用应用于对象EG的DisplayName
属性
[DisplayName("My Custom Label")] public class ChildViewModel { }
输出:
我知道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
,它返回我想要检查DisplayName
属性的对象。
我遇到的第一个问题是当我试图用razor调用这个方法时:
@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
东西,因为我真正需要的是生成要在
标记之间注入的文本。 最终代码如下。 再次感谢Sylon帮助我解决这个问题。
public static IHtmlString LegendTextFor(this HtmlHelper html, Expression<Func> 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; } }
我刚刚为标签创建了一个自定义的Html帮助程序,可以执行您想要的操作:
Html助手:
public static class HtmlHelperExtensions { public static MvcHtmlString LabelForCustom(this HtmlHelper html, Expression> expression) { ModelMetadata metadata = ModelMetadata.FromLambdaExpression(expression, html.ViewData); string customDisplayName = null; var value = expression.Compile().Invoke(html.ViewData.Model); if (value != null) { var attribute = value.GetType().GetCustomAttributes(typeof(DisplayNameAttribute), false) .Cast() .FirstOrDefault(); customDisplayName = attribute != null ? attribute.DisplayName : null; } string htmlFieldName = ExpressionHelper.GetExpressionText(expression); string labelText = metadata.DisplayName ?? customDisplayName ?? metadata.PropertyName ?? htmlFieldName.Split('.').Last(); if (String.IsNullOrEmpty(labelText)) { return MvcHtmlString.Empty; } TagBuilder tag = new TagBuilder("label"); tag.Attributes.Add("for", html.ViewContext.ViewData.TemplateInfo.GetFullHtmlFieldId(htmlFieldName)); tag.SetInnerText(labelText); return MvcHtmlString.Create(tag.ToString(TagRenderMode.Normal)); } }
我的示例模型:
public class Parent { public object Child { get; set; } } [DisplayName("yo")] public class Child { public int Id { get; set; } }
视图:
@Html.LabelForCustom(m => m.Child) @*prints yo*@