简体   繁体   中英

Using a dictionary lookup with Html.DisplayFor in an ASP.NET View

I'm learning to write MVC websites in C# with ASP.NET and the Entity Framework.

However, I'm struggling to write a dictionary lookup that would work with the Html.DisplayFor method.

Say I have the following two models:

public class Dog
{
    public int Id;
    public string Name;
    public int BreedId;
    (...)
}

public class Breed
{
    public int Id;
    public string Name;
    (...)
}

Then, somewhere in the controller, I'm creating a dictionary containing all the Breeds , indexed by the Id , and assigning it to ViewBag.Breeds .

In the Dogs/Index View, I use something like that:

@model IEnumerable<App.Models.Dog>

<table>
    @foreach (var item in Model)
    {
        <tr>
            <td>
                @Html.DisplayFor(modelItem => item.Name)
            </td>
            <td>
                @(ViewBag.Breeds[item.BreedId].Name)
            </td>
        </tr>
    }
</table>

And it generates a table of the Dogs and their Breeds , as intended.

However, if I try to use the dictionary lookup inside the Html.DisplayFor method, I get an error because an expression tree may not contain a dynamic operation :

@Html.DisplayFor(modelItem => ViewBag.Breeds[item.BreedId].Name)

Casting it to an explicitly typed dictionary doesn't work either:

@Html.DisplayFor(modelItem => ((Dictionary<int, Breed>)ViewBag.Breeds)[item.BreedId].Name)

Is there a way to make it work?

You should check out this question which explores why DisplayFor has such a funny syntax. It isn't just a simple function that accepts a string. It accepts an expression, which is never executed but parsed, so that the Razor engine can find one of the model's properties and all of its attributes-- that is how is discovers scaffolding and knows how to render a model member.

Bottom line is-- you can't just put any old string in DisplayFor . But then again, you shouldn't need to-- to display a string, you don't need it.

Option 1

Instead of

@Html.DisplayFor(modelItem => ViewBag.Breeds[item.BreedId].Name)

Just use

@ViewBag.Breeds[item.BreedId].Name

or if your breed names might contain a < or & character, you might need to HTML-escape them, so use

@Html.Encode(ViewBag.Breeds[item.BreedId].Name)

Option 2

If you really want to take advantage of DisplayFor and MVC scaffolding, add the desired computed field to the model itself, and reference it plainly in the view.

public class Dog
{
    public int Id;
    public string Name;
    public int BreedId;

    [Display(Name = "Breed Name")]  //Optional scaffolding attributes
    public string BreedName
    {
        get 
        {
            return ViewBag.Breeds[BreedId].Name;
        }
    }
}

and in your view

@Html.DisplayFor(modelItem => item.BreedName)

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM