超文本标记语言标签使用对象的DisplayName而不是属性
本文关键字:属性 DisplayName 标签 对象 超文本标记语言 | 更新日期: 2023-09-27 18:08:43
给定如下视图模型:
public class ParentViewModel
{
public object ChildViewModel { get; set; }
}
如果我这样使用Html.LabelFor
@Html.LabelFor(model => model.ChildViewModel)
我将得到这样的输出:
<label for="Model_ChildViewModel">ChildViewModel</label>
我实际上想要的是生成的标签使用应用于对象的DisplayName
属性,例如
[DisplayName("My Custom Label")]
public class ChildViewModel
{
}
,输出为:
<label for="Model_ChildViewModel">My Custom Label</label>
我理解Html.LabelFor
方法接受一个期望属性的表达式,它将在该属性上查找DisplayName
属性,而不是对象本身。
我已经创建了一个Html助手方法来实现我想要的,看起来像这样:
public static IHtmlString CreateLabel<TModel>(this HtmlHelper html, Func<TModel, object> 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
属性的对象。
我遇到的第一个问题是当我试图在razor中像这样调用这个方法时:
@Html.CreateLabel(model => model.ChildObject)
我得到以下错误:
The type arguments for method 'CreateLabel<TModel>(this HtmlHelper,
Func<TModel, object>) cannot be inferred from usage. Try specifying
the arguments explicitly.'
所以我这样调用这个方法:
@{ Html.CreateLabel<ChildViewModel>(model => model.ChildObject); }
但是没有渲染。如果我使用调试器逐步执行我的助手方法,则会生成标签标记,但在呈现页面时什么也不显示。
我的问题是:
- 我如何修复这个生成标签到我的视图?
- 我必须做些什么才能推断出泛型参数?
- 是否有任何方法来编写Html助手做同样的事情,但使用表达式?我没有使用表达式的经验,所以不知道从哪里开始。
我想我应该张贴最后的代码,因为我做了一些小的改变。首先,我查看了一下MVC源代码中的帮助程序,并决定根据所提供的示例将该方法分成三个独立的方法。我还删除了所有的TagBuilder
的东西,因为所有我真正需要的是生成的文本之间注入的<legend></legend>
标签。最终代码如下。再次感谢Sylon对我的帮助。
public static IHtmlString LegendTextFor<TModel, TObject>(this HtmlHelper<TModel> html, Expression<Func<TModel, TObject>> expression)
{
return LegendTextHelper(html,
ModelMetadata.FromLambdaExpression(expression, html.ViewData),
ExpressionHelper.GetExpressionText(expression),
expression.Compile().Invoke(html.ViewData.Model));
}
private static IHtmlString LegendTextHelper<TModel, TObject>(this HtmlHelper<TModel> 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<T>(this T obj)
{
if (obj != null)
{
var attribute = obj.GetType()
.GetCustomAttributes(typeof(DisplayNameAttribute), false)
.Cast<DisplayNameAttribute>()
.FirstOrDefault();
return attribute != null ? attribute.DisplayName : null;
}
else
{
return null;
}
}
我刚刚为label创建了一个自定义Html帮助器,它可以做你想做的事情:
Html辅助:
public static class HtmlHelperExtensions
{
public static MvcHtmlString LabelForCustom<TModel, TValue>(this HtmlHelper<TModel> html, Expression<Func<TModel, TValue>> 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<DisplayNameAttribute>()
.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*@