11

I have an Item class. I have around 10-20 derivatives of it each containing different types of data. Now when it comes to rendering different types of Item, I'm forced to use likes of:

<div> 
@if (Model is XItem)
{
   ... rendering logic 1 ...
}
@if (Model is YItem)
{
   ... rendering logic 2 ...
}
@if (Model is ZItem)
{
   ... rendering logic 3 ...
}
... goes on and on forever ...
</div>

Unfortunately @Html.DisplayFor() does not work in this case because the Model is type of Item, DisplayTemplates\Item.cshtml is displayed.

HTML helpers don't help either because of the same "if/is" chain.

I could incorporate rendering logic inside the classes themselves, and call @Model.Render() but they belong to business logic, not presentation. It would be a sin.

There is only one option of @Html.Partial(Model.GetType().Name) but it feels wrong. You expect a solution without meta-magic. Is there a better way?

Sedat Kapanoglu
  • 46,641
  • 25
  • 114
  • 148
  • This is a very good question, I've not run into this yet. I hope that someone like Darin sees this one. But I'm just curious. If you built a display named `XItem`, it doesn't get chosen instead? **I'm guessing you're saying you've already tried that.** – Mike Perrenoud Oct 10 '13 at 13:09
  • @neoistheone I've tried that and no it's not picked by MVC. It uses whatever the declared type is. – Sedat Kapanoglu Oct 10 '13 at 13:11
  • I see what you're saying. Because the `@model` declaration is `Item` it always picks up that view. – Mike Perrenoud Oct 10 '13 at 13:12
  • Well, how much does the render logic differ? If it is quite different then you may not be left with many alternatives, perhaps a partial view for each type at best – musefan Oct 10 '13 at 13:12
  • 1
    @musefan I'm ok having multiple files for each derived type. I'm not ok with writing if statements to decide on include which. – Sedat Kapanoglu Oct 10 '13 at 13:14
  • 2
    Can you be more specific to illustrate why you have classes designed like this? If you can give us more info, maybe it would be easier to provide a solution. So far it kinda sounds like a bad architecture decision... – walther Oct 10 '13 at 13:14
  • May be you can try template. You can have seperate template for each derivative. You may require to have same template pattern to avoid branching, like if you are using edit template. you can called your template file name with EditDerivative1.cshtml, EditDerivative2.cshtml, EditDerivative3.cshtml etc – Miller Oct 10 '13 at 13:16
  • 2
    Using display templates for the derived types will work, I have an application that does this. – Jamie Ide Oct 10 '13 at 13:23
  • For your problem EditorForModel(Model,"display"+ Model.GetType().Name) may do. Same thing can be used for display with DisplayForModel. This will avoid multiple if's – Miller Oct 10 '13 at 13:27
  • 2
    Folks I'm so sorry apparently DisplayFor actually works and I missed it due to a coding error. So `DisplayFor` is still the way to go. Thanks for delving into this. – Sedat Kapanoglu Oct 10 '13 at 13:35

2 Answers2

6

Use Display Templates.

Inside your ~/Views/Shared/DisplayTemplates folder you can add a view with the same name as your type.

When you do @Html.DisplayFor(item) you'll get the view related to that specific type.

UPDATE

I just saw your comment RE DisplayFor so if this doesn't help i'll remove my answer.

Jamie Dixon
  • 53,019
  • 19
  • 125
  • 162
5

I think your approach is fine. You can make it better with an extension method like this:

public static MvcHtmlString GetTypePartial<T>(this HtmlHelper htmlHelper, T model, string viewPrefix = "")
{
    string typeName = typeof (T).Name;
    string viewName = string.Concat(viewPrefix, typeName);
    return htmlHelper.Partial(viewName, model);
}
Ufuk Hacıoğulları
  • 37,978
  • 12
  • 114
  • 156