ASP.net MVC - displaying a list containing different types, with a different view for each type

Imagine that I have a list of objects that implement the ISummary interface. The objects in this list MAY have additional properties, i.e.

public interface ISummary { Guid Id {get;set;} string Title {get;set;} DateTime Created {get;set;} } public class GigSummary: ISummary { Guid Id {get;set;} string Title {get;set;} DateTime Created {get;set;} string VenueName {get;set} string Band {get;set;} } public class NewsSummary: ISummary { Guid Id {get;set;} string Title {get;set;} DateTime Created {get;set;} string Author{get;set} } 

Now I am passing this list of Gigs and News Summary objects (like the ISummary list) for presentation as a model.

I want to display this list using a partial for each type contained in the list.

How to do this is ASP.NET MVC?

+4
source share
5 answers

The most obvious way I can think of is to do something like:

  foreach(ISummary summ in listOfISummary) { Html.RenderPartial(String.Fomat("~/Views/Shared/{0}Renderer.ascx", summ.GetType.ToString()), summ, ViewData);%> } 

and create a strongly typed view with a naming convention, for example NewsSummaryRenderer.ascx.

I expect that you can port this to a helper method, but I would add it to one of the existing helpers using the extension method instead of putting it in the code behind, as suggested earlier.

+8
source

You can put a helper method in view codebehind and then do something like:

 Type modelType = this.Model.GetType(); if (modelType == typeof(NewsSummary)) this.RenderPartial("newspartial", this.Model as NewsSummary); else if (modelType == typeof(GigSummary)) this.RenderPartial("gigpartial", this.Model as GigSummary); 
0
source

Lewis is on the right track. I would take a slightly different approach: both widgets are distributed from a common base class that provided information about name names. Then add an extension method to the page class to "render the widget", which can get the corresponding look.

Check out the Kona ASP.NET MVC sample application for a working example of this concept.

0
source

I would create the HtmlHelper extension that did this. Here's some pseudo code that looks amazingly similar to C # and can really work:

 public static void TemplatedList<T>(this HtmlHelper me, IEnumerable<T> items, IDictionary<Type, Action<T>> templates) { foreach(var item in items) { var template = templates[item.GetType()]; if(template != null) template(item); } } 

I would use it as follows:

 <% HtmlHelper.TemplatedList(ViewData.Model, new Dictionary { {typeof(GigSummary), x => %> <div class="gigSummary"> SUP! GIG ANNOUNCEMENT FOR <%= x.Band %>!! What: <%= x.Title %> When: <%= x.Created %> Who: <%= x.Author %> </div> <%} // add more type/template pairs here }); %> 
0
source

Here is a simple extension method that you can create to extract only the types you need:

 public static class Extensions { public static IEnumerable<U> ExtractOfType<U, T>(this IEnumerable<T> list) where T : class where U : class { foreach (var item in list) { if (typeof(U).IsAssignableFrom(item.GetType())) { yield return item as U; } } } } 

Test:

 public interface IBaseInterface { string Foo { get; } } public interface IChildInterface : IBaseInterface { string Foo2 { get; } } public interface IOtherChildIntreface : IBaseInterface { string OtherFoo { get; } } public class BaseImplementation : IBaseInterface { public string Foo { get { return "Foo"; } } } public class ChildImplementation : IChildInterface { public string Foo2 { get { return "Foo2"; } } public string Foo { get { return "Foo"; } } } public class OtherChildImplementation : IOtherChildIntreface { public string OtherFoo { get { return "OtherFoo"; } } public string Foo { get { return "Foo"; } } } 

....

  List<IBaseInterface> b = new List<IBaseInterface>(); b.Add(new BaseImplementation()); b.Add(new ChildImplementation()); b.Add(new OtherChildImplementation()); b.Add(new OtherChildImplementation()); foreach (var s in b.ExtractOfType<IOtherChildIntreface, IBaseInterface>()) { Console.WriteLine(s.GetType().Name); } 

This will get all the items in the list that have the derived type that you are looking for. So, in your controller, go all the way to the view. Then, partial views that accept an IEnumerable of the type required by the partial, and in your main view, call this extension method and pass the result to these separate partial views.

0
source

Source: https://habr.com/ru/post/1285803/


All Articles