3

I am trying to utilize the DisplayTemplates feature in razor-engine to automate rendering my display views.

I scan my Model to find the correct ModelMetadata for each property that I want to display. But I am not able to render the properties using Html.DisplayFor correctly.

I tried to display my property like so

// First I find the ModelMetadata for the property
// I call this statement in a loop and each iteration I pass a different PropertyName to get the correct model
ModelMetadata columnMetadata = elementsMetadata.First(x => x.PropertyName == column.PropertyName);

// I attempted to render the columnMetadata object like so
Html.DisplayFor(x => columnMetadata.Model)

The above code works "in term of displaying the correct value" However it does not use the correct DisplayTemplate which is causing the incorrect format.

For example I have an editor template called Currency.cshtml which simply display Model.ToString("C"). I also have another display template called Status.cshtml which accepts boolean value and return "Active" or "Inactive". Both display-template are located in ~/Views/Shared/DisplayTemplates.

But for some reason Html.DisplayFor() isn't looking for the proper template. Here is an example of one of my view-models

public class ViewModel
{
    public string Name { get; set; }

    [DataType(DataType.Currency)]
    public decimal Rate { get; set; }

    [DataType("Status"), DisplayName("Status")]
    public bool Active { get; set; }
}

Currently my view shows a disabled checkbox for the Active property and a non-formatted number for my Rate property.

How can I correctly display ModelMetadata object where the correct display-template is used based on the property data-type?

Sir Rufo
  • 18,395
  • 2
  • 39
  • 73
Junior
  • 11,602
  • 27
  • 106
  • 212
  • `ModelMetadata` contains a `DataTypeName` property which should give you the value of `DataType` (and you could use that in the 2nd argument of `DisplayFor()`) –  Aug 07 '18 at 04:50
  • @StephenMuecke that worked! As always your awesome. But is this the right way to display the property or is there a better method to use? – Junior Aug 07 '18 at 04:53
  • I take it this is related to your [previous question](https://stackoverflow.com/questions/51677304/how-can-i-get-the-metadata-of-the-items-in-a-collection-in-razor-view-engine), where your want just one view with `@model object`? –  Aug 07 '18 at 04:56
  • @StephenMuecke yes. I got everything to work except for 2. The proper way to display the `ModelMetadata` object. And how to correctly use `IMetadataAware` to add values to the `AdditionalValues` to the property which is decorated with the attribute that implements the `IMetadataAware` – Junior Aug 07 '18 at 04:58
  • Only just seen that comment on my other answer. Not sure what you may have done wrong, but I'll give you are more detailed example of how it works a bit later (will ping you in that answer). –  Aug 07 '18 at 05:01
  • @StephenMuecke Thank you so much. When time permits, please post an answer here also and I'll gladly accept it. – Junior Aug 07 '18 at 05:03
  • As for _is it the right way_? Well it works :) (and you can also use `[UIHint]` attributes - e.g. `[UIHint("Status")]public bool Active { get; set; }`), but as I noted in the previous question, using a custom `HtmlHelper` method would be better and give more flexibility –  Aug 07 '18 at 05:04

1 Answers1

1

ModelMetadata contains a DataTypeName property, which contains the value generated by the DataTypeAttribute, which will be "Currency" for your Rate property and "Status" for you Status property. You can use this value in the 2nd argument of DisplayFor()

ModelMetadata columnMetadata = elementsMetadata.First(x => x.PropertyName == column.PropertyName);
string template = columnMetadata.DataTypeName;
Html.DisplayFor(x => columnMetadata.Model, template)

Note also that you can use the UIHintAttribute which also sets the value of DataTypeName, for example

[Display(Name = "Status")] // use this rather that [DisplayName]
[UIHint("Status")]
public bool Active { get; set; }