Display template not used for interface

随声附和 提交于 2019-12-10 22:19:21

问题


I'm having a problem with display templates and dealing with interfaces and objects which implement the interface. In the example I have many objects, which I want to be rendered in a fixed way, I decided to create an interface and reference this in the view which I've decided to put into the shared display templates folder. DisplayFor doesn't seam to work for objects passed to it which implement the interface in the view, does any one know a solution to this.

Its probably easier to explain via code so I've wrote a quick example. The base interface and two classes which inherit from it:

public interface IPet
{
    String Name { get; }
}

public class Dog : IPet
{
    public String Name { get; set; }
}

public class Cat : IPet
{
    public String Name { get; set; }
}

The example display template in shared display templates

@model IPet

<div>@Model.Name</div>

The example view model to be passed to the view

public class VM
{
    public IPet Master { get; set; }
    public IEnumerable<IPet> Minions { get; set; }
}

The controller (in this case to create mock information)

    public ActionResult Index()
    {
        var viewModel = new VM();
        viewModel.Master = new Cat(){Name = "Fluffy"};

        var minions = new List<IPet>();

        minions.Add(new Dog(){Name = "Dave"});
        minions.Add(new Dog(){Name = "Pete"});
        minions.Add(new Cat(){Name = "Alice"});

        viewModel.Minions = minions;

        return View(viewModel);
    }

and finally the view which I would expect DisplayFor to work

@model ViewInheritance.Models.VM

<h2>Master</h2>

@Html.DisplayFor(x => x.Master)

<h2>Minions</h2>

@Html.DisplayFor(x => x.Minions)

Given that all the objects are are defined in the view model as the interfaces, howcome it fails to use the display template?

One solution I have found is to simply use the code

@Html.DisplayFor(x => x.Master, "IPet")

To recap, the question is:

Why does this happen? Is there a way to make DisplayFor correctly work out that a type of Cat which implements IPet should in fact be looking at the common shared view IPet.cshtml?

Thanks


回答1:


Starting a new MVC application and fixing the code to actually compile the view renders fine. It also renders fine when moving the view into the shared folder.

I Added setter to IPet:

public interface IPet
{
    String Name { get; set; }
}

I updated implementation and added public accessors:

public class Dog : IPet
{
    public String Name { get; set; }
}

public class Cat : IPet
{
    public String Name { get; set; }
}

I left your VM alone and also did not change any code in your View. Pressing F5, running the MVC application rendered the results as expected (See image).




回答2:


Unfortunately, I don't think ASP.NET MVC currently supports automatically selecting templates based on implemented interfaces. I think this makes sense because a class could implement multiple interfaces, so if you had templates for more than one of those interfaces, which one should the framework choose?

You could use a base class instead of an interface if your design can cope with it:

  • Change IPet to a (possibly abstract) class.
  • Change IPet.cshtml to Pet.cshtml.

Otherwise I think you'll just need to explicitly tell the framework which template to use. Here are some options:

  • Decorate the view model properties with [UIHint].
  • Specify the template in your calls to your HtmlHelper methods such as DisplayFor.
  • Make your own ModelMetadataProvider and change the TemplateHint property of the resulting ModelMetadata.


来源:https://stackoverflow.com/questions/9127772/display-template-not-used-for-interface

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!