1

I am working on a project where I need to output a few hundred properties on to the screen. To save myself lots of tedious markup, I decided to use reflection.

//markup removed to keep this concise
@for (var i = 0; i < Model.SiteAndJobDetails.GetType().GetProperties().Count(); i++)
{
  @Model.SiteAndJobDetails.GetType().GetProperties()[i].Name
  @Model.SiteAndJobDetails.GetType().GetProperties()[i].GetValue(Model.SiteAndJobDetails, null)
}

Although slower to render, this will save me writing out about 2 hundred properties and values with HTML helpers. At least, that was the plan. However, I need to use @Html.DisplayNameFor or something similar to pick up the Display attribute value from the property.

My intial thoughts were

@Html.DisplayNameFor(m=>@Model.SiteAndJobDetails.GetType().GetProperties()[i].Name)

But that does not work, I would imagine because I am using reflection here to get the property name. Is there another way?

Lotok
  • 4,517
  • 1
  • 34
  • 44

4 Answers4

2

You can get it using the Metadata (that's what the framework does anyway):

string displayName = ViewData.ModelMetadata.Properties
      .Where(x => x.PropertyName == Model.SiteAndJobDetails.GetType()
                                   .GetProperties()[i].Name)
      .SingleOrDefault()
      .DisplayName;
Andrei V
  • 7,306
  • 6
  • 44
  • 64
  • Thanks for pointing me in the right direction. Your syntax was a little off so I will edit the answer for future searchers. Once the edit is accepted I will accept. Thanks very much for your help – Lotok Mar 27 '14 at 12:20
  • @James, the edit was rejected. Consider adding your solution either as an answer or an edit in your original post. – Andrei V Mar 27 '14 at 12:28
2

@Andrei was correct to use the ViewData.ModelMetadata but had the syntax slightly off. The correct syntax is

@ViewData.ModelMetadata.Properties.First(x => x.PropertyName == "SiteAndJobDetails")
.Properties.SingleOrDefault(x => x.PropertyName == Model.SiteAndJobDetails.GetType().GetProperties()[i].Name)
.DisplayName

The final solution is to check the property exists, if it does use it, otherwise use the property name

@if (!string.IsNullOrEmpty(@ViewData.ModelMetadata.Properties.First(x => x.PropertyName == "SiteAndJobDetails").Properties.SingleOrDefault(x => x.PropertyName == Model.SiteAndJobDetails.GetType().GetProperties()[i].Name).DisplayName))
{
    @ViewData.ModelMetadata.Properties.First(x => x.PropertyName == "SiteAndJobDetails").Properties.SingleOrDefault(x => x.PropertyName == Model.SiteAndJobDetails.GetType().GetProperties()[i].Name).DisplayName
}
else
{
    @Model.SiteAndJobDetails.GetType().GetProperties()[i].Name
}
Lotok
  • 4,517
  • 1
  • 34
  • 44
0

Alternatively, add this to your razor:

@functions {
string R<TCLASS>(Expression<Func<TCLASS, Object>> expression) //Lambda = x => x.TPROPERTY
{
    var memberExpression = expression.Body as MemberExpression;
    if(memberExpression == null)
    {
        memberExpression = (MemberExpression) ((UnaryExpression)expression.Body).Operand;
    }

    return memberExpression.Member.Name;
}
}

Then you can:

@(R<ModelClassName>(x => x.PropertyName)) //Outputs "PropertyName"

I like using this when writing JavaScript that receives JSON. It lets you do this:

<script>
    function recieveJsonResult(classNameDto) {
        var classProperty = classNameDto.@(R<ClassNameDto>(x => x.PropertyName));
    }
</script>

This way you get autocomplete inside the lambda and you are free to rename the property without worrying about breaking your front end code.

3dot
  • 21
  • 4
0

I prefer this answer: https://stackoverflow.com/a/31448493/9266796

Updated to today's syntax:

var displayName = property.GetCustomAttribute<DisplayAttribute>().Name;

Or this one's even easier actually: https://stackoverflow.com/a/19940277/9266796

@Html.Label(property.Name);
Johan Maes
  • 1,161
  • 13
  • 13
  • This is certainly easy, except it doesn't work if your class has properties that are themselves classes. In that case you'll need to build the appropriate dot-notation for the property chain so that you have the correct name/id for the form control. – BrianS Jan 08 '20 at 23:57