Html.Labelfor使用对象不是财产的显示名称 [英] Html.Labelfor use DisplayName of object not property

查看:221
本文介绍了Html.Labelfor使用对象不是财产的显示名称的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

由于这样的视图模型:

 公共类ParentViewModel 
{
公共对象ChildViewModel {得到;组; }
}

如果我用 Html.LabelFor 是这样的:

  @ Html.LabelFor(型号=> model.ChildViewModel)

我会得到这样的输出:

 <标签=Model_ChildViewModel> ChildViewModel< /标签> 



我真正想要的,虽然是生成的标签使用显示名称属性应用到对象EG

  [DisplayName的(我的自定义标签)] 
公共类ChildViewModel
{
}

用的输出:

 <标签=Model_ChildViewModel>我的自定义标签< /标签> 



据我所知, Html.LabelFor 方法采用期望一个属性的表达式,它会寻找在该属性,而不是对象本身的显示名称属性。



我已经创建了一个HTML辅助方法来实现我想要的东西,看起来像这样:

 公共静态IHtmlString CreateLabel<的TModel> (这个HTML的HtmlHelper,Func键<的TModel,对象> FUNC)
式的TModel:类
{
TagBuilder TB =新TagBuilder(标签);

VAR模型= html.ViewData.Model为的TModel;
如果(型号!= NULL)
{
obj对象= FUNC(模型);
如果(OBJ!= NULL)
{
var属性= obj.GetType()。GetCustomAttributes(
typeof运算(DisplayNameAttribute),真)
.FirstOrDefault()作为DisplayNameAttribute;

如果(属性!= NULL)
{
tb.InnerHtml = attribute.DisplayName;
返回MvcHtmlString.Create(tb.ToString());
}
,否则
{
tb.InnerHtml = obj.ToString();
返回MvcHtmlString.Create(tb.ToString());
}
}
}

tb.InnerHtml = html.ViewData.Model.ToString();
返回MvcHtmlString.Create(tb.ToString());
}



而不是采取一种表现,帮助我需要一个 FUNC<的TModel,对象> 返回,我想检查显示名称属性对象



我的第一个问题是,当我试图调用这个方法在这样的剃刀:

  @Html。 CreateLabel(型号=> model.ChildObject)

我收到以下错误:

 的类型参数的方法CreateLabel<的TModel>(此的HtmlHelper,
Func键<的TModel,对象>)不能从使用中推断出来。尝试指定
的论点明确'



所以我这样调用而不是方法:

  @ {Html.CreateLabel< ChildViewModel>(型号= GT; model.ChildObject); } 



但没有得到呈现。如果我使用调试器来逐步通过我的助手方法,正在生成标签标记,但是当我的网页呈现上什么都没有。



所以我的问题是:




  • 我如何解决这个问题,生成标签,我的看法?

  • 怎么做我必须做的使泛型参数可以推断?

  • 有没有办法写HTML辅助做同样的事情,但使用的是体现在哪里?我使用表达式所以不知道从哪里开始没有经验。



更新



我想我会发布最终的代码,因为我做了一些小的改动。首先,我看了一眼在MVC源代码中的助手,并决定该方法分为符合三种不同的方法使用所提供的例子。我也删除了所有的 TagBuilder 的东西,我真正需要的是产生是℃之间被注入的文本;传奇>< /传说> 标记。最终的代码如下。再次,感谢Sylon帮助我这个

 公共静态IHtmlString LegendTextFor<的TModel,TObject的>(此的HtmlHelper<的TModel> HTML,表达< Func键<的TModel,TObject的>>表达式)
{
返回LegendTextHelper(HTML,
ModelMetadata.FromLambdaExpression(表达式,html.ViewData),
ExpressionHelper .GetExpressionText(表情),
expression.Compile()调用(html.ViewData.Model))。
}

私有静态IHtmlString LegendTextHelper<的TModel,TObject的>(此的HtmlHelper<的TModel> HTML,ModelMetadata元,串htmlFieldName,TObject的值)
{
串resolvedLabelText = metadata.DisplayName? value.GetDisplayName()? metadata.PropertyName? htmlFieldName.Split('。')最后()。

如果(String.IsNullOrEmpty(resolvedLabelText))
返回MvcHtmlString.Empty;

返回MvcHtmlString.Create(resolvedLabelText);
}

私人静态字符串GetDisplayName< T>(这件T OBJ)
{
如果(OBJ!= NULL)
{
var属性= obj.GetType()
.GetCustomAttributes(typeof运算(DisplayNameAttribute),FALSE)
.Cast< DisplayNameAttribute>()
.FirstOrDefault();

返回属性!= NULL? attribute.DisplayName:空;
}
,否则
{
返回NULL;
}
}


解决方案

我刚刚创建的自定义HTML帮手的标签,你想要做什么:



的HTML帮助:

 公共静态类HtmlHelperExtensions 
{

公共静态MvcHtmlString LabelForCustom<的TModel,TValue>(此的HtmlHelper<的TModel> HTML,表达< Func键<的TModel,TValue>>表达式)
{
ModelMetadata元= ModelMetadata.FromLambdaExpression(表达式,html.ViewData);

字符串customDisplayName = NULL;

VAR值= expression.Compile()调用(html.ViewData.Model)。

如果(值!= NULL)
{
var属性= value.GetType()GetCustomAttributes(typeof运算(DisplayNameAttribute),FALSE)
.Cast< DisplayNameAttribute> ()
.FirstOrDefault();

customDisplayName =属性!= NULL? attribute.DisplayName:空;
}

串htmlFieldName = ExpressionHelper.GetExpressionText(表达);
串LabelText的= metadata.DisplayName? customDisplayName? metadata.PropertyName? htmlFieldName.Split('。')最后()。
如果(String.IsNullOrEmpty(LabelText的))
{
返回MvcHtmlString.Empty;
}

TagBuilder标签=新TagBuilder(标签);
tag.Attributes.Add(代表,html.ViewContext.ViewData.TemplateInfo.GetFullHtmlFieldId(htmlFieldName));
tag.SetInnerText(LabelText的);
返回MvcHtmlString.Create(tag.ToString(TagRenderMode.Normal));
}
}



我的例子模型:

 公共类父
{
公共对象儿童{搞定;组; }
}

[DisplayName的(哟)]
公共类儿童
{
公众诠释标识{搞定;组; }
}

查看:

  @ Html.LabelForCustom(M = GT; m.Child)@ *打印哟* @ 


Given a view model like this:

public class ParentViewModel
{
    public object ChildViewModel { get; set; }
}

If I use Html.LabelFor like this:

@Html.LabelFor(model => model.ChildViewModel)

I would get an output like this:

<label for="Model_ChildViewModel">ChildViewModel</label>

What I actually want though is for the generated label to use the DisplayName attribute applied to the object E.G.

[DisplayName("My Custom Label")]
public class ChildViewModel
{
}

with an output of:

<label for="Model_ChildViewModel">My Custom Label</label>

I understand that the Html.LabelFor method takes an expression that expects a property and it will look for the DisplayName attribute on that property rather than the object itself.

I have created an Html helper method to achieve what I want that looks like this:

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());
    }

Instead of taking an expression, my helper takes a Func<TModel, object> which returns the object that I want to check for the DisplayName attribute.

The first problem I had was when I tried to call this method in razor like this:

@Html.CreateLabel(model => model.ChildObject)

I get the following error:

The type arguments for method 'CreateLabel<TModel>(this HtmlHelper,
Func<TModel, object>) cannot be inferred from usage. Try specifying
the arguments explicitly.'

So I call the method like this instead:

 @{ Html.CreateLabel<ChildViewModel>(model => model.ChildObject); }

but nothing gets rendered. If I use the debugger to step through my helper method, the label tag is being generated but nothing is shown when my page is rendered.

So my questions are:

  • How do I fix this to generate the label to my view?
  • What do I have to do so that the generic parameter can be inferred?
  • Is there any way to write the Html helper to do the same thing but using an expression? I have no experience using expressions so don't know where to start.

Update

I thought I'd post the final code as I made a few minor changes. First of all I took a look at the helpers in the MVC source code and decided to split the method into three separate methods in line with the provided examples. I also removed all the TagBuilder stuff as all I really needed was to generate the text that was to be injected between the <legend></legend> tags. The final code is below. Once again, thanks to Sylon for helping me out with this.

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;
    }
}

解决方案

I just created a custom Html helper for label that does what you want:

Html Helper:

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));
    }
}

My example model:

public class Parent
{
    public object Child { get; set; }
}

[DisplayName("yo")]
public class Child 
{
   public int Id { get; set; }
}

View:

@Html.LabelForCustom(m => m.Child)  @*prints yo*@

这篇关于Html.Labelfor使用对象不是财产的显示名称的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆