Asp.Net MVC Полиморфизм изнутри Посмотреть - PullRequest
1 голос
/ 23 марта 2012

Чтобы дать вам пример, с которым вы все должны быть знакомы, представьте, что вы создаете страницу на Facebook в Asp.Net MVC. На стене есть различные виды постов (например, обновления статуса, фотографии, видео, ссылки и т. Д. Все они отображаются внизу стены и отображаются по-разному, в зависимости от того, какой пост они представляют. Я создаю нечто похожее на это, и мне кажется, что самый элегантный способ сделать это с полиморфизмом. Я перехожу через типы Post и вызываю метод рендеринга, который реализует каждый подтип. Я сделал что-то подобное в коде позади Web Forms, но Я не могу понять, как сделать это в MVC, не смешивая проблемы, если не считать гигантского списка блоков if else.

@foreach(Post post in Model.Posts)
{
    if(post is A)
    {
        <div>Different Content</div>
    }
    else if(post is B)
    {
        <div>Different Content</div>
    }
    else if(post is C)
    {
        <div>Different Content</div>
    }
}

вместо

@foreach(Post post in Model.Posts)
{
    post.render();
}

Как мне получить что-то более подходящее, как вторая часть?

Ответы [ 4 ]

5 голосов
/ 23 марта 2012

Дайте родительскому объекту свойство "PartialViewPath", и в каждом дочернем классе свойство PartialViewPath возвращает строку, представляющую путь к представлению для этого типа публикации.Тогда, на вашем главном экране, это так просто:

@foreach (var post in Model.Posts)
{
    Html.RenderPartial(post.PartialViewPath)
}
3 голосов
/ 26 ноября 2013

Для этого вы можете использовать шаблонные HTML-помощники:

  1. Создать каталог DisplayTemplates в Views/YourView.
  2. Добавить строго типизированное представление с именем <model class name>.cshtml (если вы используете Razor). Это представление будет использовано для визуализации вашей модели позже.
    Для вашего примера вам понадобятся 3 шаблона: A.cshtml, B.cshtml, C.cshtml.
  3. Чтобы отобразить модель с определенным выше видом, используйте Html.DisplayFor() внутри родительского представления.
2 голосов
/ 23 марта 2012

Вы можете использовать частичное представление, которое основано на модели, которая в интерфейсе, предоставляющем метод Render.

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

проблема, конечно, заключается в том, что вам необходимо сгенерировать содержимое в методе Render с использованием Html.Raw или чего-то подобного, поскольку фактический html внутри собственно View является статическим.

Но тогда само представление будет выглядеть примерно так:

@Html.Raw(Model.Render()) 

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

Обновление: у вас будет интерфейс

public interface ContentView
{
    public string Render();
}

И у вас будет, например, 2 класса, расширяющих этот интерфейс:

public class TextView : ContentView
{
    public string Render()
    {
        return "TextView!";
    }
}

И

public class HtmlView : ContentView
{
    public string Render()
    {
        return "<strong>HtmlView!</strong>";
    }
}

И ваш частичный вид называется ContentView

@model ContentView
@Html.Raw(Model.Render());

Затем ваш ActionResult в вашем контроллере:

public ActionResult ShowPosts()
{

   List<ContentView> posts = PostRepository.GetPosts();

   return posts;
}

И ваш основной вид:

@model List<ContentView>

@foreach(var contentView in Model) {

    @Html.PartialView("ContentView", contentView);

}

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

0 голосов
/ 23 марта 2012

Я сделал нечто подобное, для этого требуются операторы if / else, но используется RenderAction, чтобы избежать внедрения HTML для каждого оператора if.

Итак, у меня определена модель:

@model SearchResultViewModel

Который содержит список IEnumerable<ContentViewModel>, затем перебирается с помощью оператора if, как у вас:

    @foreach (var result in Model.Results)
     {
        if (result is VideoViewModel)
        { Html.RenderAction("Item", "Video", new { item = result }); }
        else if (result is PodcastViewModel)
        { Html.RenderAction("Item", "Podcast", new { item = result }); }
        else
        { Html.RenderAction("Item", "Article", new { item = result }); }
    }

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

В моем сценарии, однако, содержание совершенно иное.

Если вы все похожи, вы можете выводить различные представления в вашем действии и использовать один вызов RenderAction.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...