ASP.net MVC - отображение списка, содержащего разные типы, с различным представлением для каждого типа - PullRequest
5 голосов
/ 05 июня 2009

Представьте, что у меня есть список объектов, которые реализуют интерфейс под названием ISummary Объекты в этом списке МОГУТ иметь дополнительные свойства, т. Е.

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}
}

Теперь я передаю этот список объектов Gigs и News Summary (в виде списка ISummary) представлению в качестве модели.

Я хочу отобразить этот список, используя разные частичные для каждого типа, содержащегося в списке.

Как я могу сделать это ASP.NET MVC?

Ответы [ 5 ]

8 голосов
/ 05 июня 2009

Самый очевидный способ, которым я могу придумать, это сделать что-то вроде:

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

и создайте строго типизированное представление с соглашением об именах, например NewsSummaryRenderer.ascx.

Я ожидаю, что вы могли бы переместить это во вспомогательный метод, но я бы добавил его к одному из существующих помощников с помощью метода расширения, а не помещал его в код, как предлагалось ранее.

0 голосов
/ 05 июня 2009

Вот простой метод расширения, который вы можете создать для извлечения нужных вам типов:

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;
            }
        }
    }
}

Тест:

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);
        }

Это позволит получить все элементы списка, которые имеют искомый тип, который вы ищете. Итак, в вашем контроллере передайте весь список на просмотр. Затем создайте частичные представления, которые принимают IEnumerable того типа, который необходим частично, и в основном представлении вызовите этот метод расширения и передайте результат этим отдельным частичным представлениям.

0 голосов
/ 05 июня 2009

Я бы создал расширение HtmlHelper, которое сделало это. Вот некоторый псевдокод, который выглядит шокирующе, как c #, и на самом деле может работать:

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);
  }
}

Я бы использовал это так:

<% 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 голосов
/ 05 июня 2009

Льюис на правильном пути. Я бы взял немного другую тактику - оба «виджета» расширяются от общего базового класса, который предоставляет информацию об именах представлений. Затем добавьте метод расширения к своему классу страницы, чтобы «отобразить виджет», который мог бы получить соответствующий вид на месте.

Посмотрите пример приложения Kona ASP.NET MVC для рабочего примера этой концепции.

0 голосов
/ 05 июня 2009

Вы можете поместить вспомогательный метод в коде представления, а затем сделать что-то вроде:

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);
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...