2

I want to display an Index style View featuring an HTML table that I populate from my @model, a List<MyViewModel>.

The MyViewModel class has a property called Status, which is a custom enum I've defined like so:

public enum MarketingEmailStatus
{
    Queued,
    Sending,
    Sent
}

When I attempt to display that property in my View like so ...

        ...

        @foreach (var item in Model)
        {
            <tr>
                <td>
                    @Html.DisplayForModel(modelItem => item.Status)
                </td>
         ...

I get an error (both in Intellisense and at run time):

Cannot convert lambda expression to type 'object' because it is not a delegate type

I tried to do item.Status.ToString() to no avail.

No doubt, I could probably take an alternative approach (i.e., just change the ViewModel to represent Status as a string and resolve this prior to sending to the view), but this feels like such a simple scenario that it should be possible. And yet after an hour of searching I've not found any solutions (other than those related to DropDownLists for which there seems to be some @Html helper methods available.)

Bob Tabor
  • 967
  • 1
  • 13
  • 23

2 Answers2

1

I see two problems with directly using @item.Status:

  • It won't respect the "display values" of those enums e.g. instead of "Code Sample", it would show "CodeSample".

  • It doesn't take into account the localization.

This looks like a very promising solution for such scenarios, in my opinion.

You can obviously just use the extension methods if point 2 is not your concern as below:

public static class EnumExtensions
{
    public static string GetDisplayName(this Enum enumValue)
    {
        FieldInfo fi = enumValue.GetType().GetField(enumValue.ToString());
        var displayAttribute = fi.CustomAttributes.FirstOrDefault(c => c.AttributeType == typeof(DisplayAttribute));
        if (displayAttribute == null) return enumValue.ToString();
        return displayAttribute.NamedArguments.FirstOrDefault(a => a.MemberName == "Name").TypedValue.Value.ToString();
    }
}
Aneeq
  • 416
  • 3
  • 15
0

In ASP.NET Core, especially in my own web application — which we both somehow have been upgrading constantly since ASP.NET Core 2.0 days — what I did was just used the variable name from Model and did a @ on it, ASP.NET Core 2.0 took care of the rest. It is quite surprising to me, as to why you are still using these Html helpers, and not the best of what ASP.NET has to offer. :-) And yes, for select element, there is a special ASP.NET Core tag helper, which takes the model and in the case of a simple text display you can do @propertyName and it will be properly written for you.

Let me share the necessary model content with you,

public class Foo {
    // Other properties
    public int Views { get; set; } 
    public PostType PostType { get; set; }
    // Other properties.
}

The enum is like this,

public enum PostType { Article, Video, CodeSample, Ebook, Other }

Now, on the View page I do the following after capturing the Model,

<!-- Content here. -->
<p>@post.PostType has @post.Views views.</p>
<!-- Content here. -->

And there, it automatically prints the string containing the enum value.

enter image description here

As you can see, the last line in the paragraph shows Article has 6 views. Which was the response for the item that I had selected. Rest of the content in the image can be ignored.

Now, as to just give an idea of a table, this would perfectly work — and it does work for my dashboard panel in the web app.

<table>
   <tr>
      <th>Id</th>
      <th>Title</th>
      <th>Status</th>
   </tr>
   @foreach (var item in Model) {
      <tr>
         <td>@item.Id</td>
         <td>@item.Name</td>
         <td>@item.Status</td>
      </tr>
   }
</table>

There is no need to bring in lambdas for such a simple task — I mean, no need for @Html helper, because Razor is enough and smart too.

Afzaal Ahmad Zeeshan
  • 15,669
  • 12
  • 55
  • 103