2012-03-23 2 views
0

모두 익숙해야하는 예제를 제공하려면 Asp.Net MVC에서 Facebook 벽 페이지를 작성한다고 상상해보십시오. 벽에는 다양한 종류의 게시물 (즉, 상태 업데이트, 사진, 비디오, 링크 등)이 있습니다. 모든 게시물은 벽 아래로 표시되며, 어떤 게시물 종류에 따라 다르게 렌더링됩니다. 이 작업을 수행하는 가장 우아한 방법은 다형성입니다. 포스트 유형을 통해 foreach하고 각 하위 유형이 구현하는 렌더링 메소드를 호출합니다. Web Forms의 코드 숨김에서 이와 비슷한 작업을했지만 나는, 만약 다른 블록의 거대한 목록을 가진 짧은 우려를 혼합하지 않고 MVC에서이 작업을 수행하는 방법을 알아낼 수 없습니다.Asp.Net MVC 다형성 내부보기

@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(); 
} 
,536을

어떻게하면 두 번째 부분과 같이 더 많은 것을 유지 보수 할 수 있습니까?

답변

2

Render 메서드를 노출하는 인터페이스에서 모델을 기반으로하는 부분 뷰를 사용할 수 있습니다.

ActionResult에서 표시하려는 콘텐츠의 올바른 유형 인이 인터페이스의 구체적인 인스턴스를 반환합니다.

물론 문제는 Html.Raw 또는 그와 유사한 것을 사용하여 Render 메서드에서 내용을 생성해야합니다. 즉, View 내부의 실제 HTML은 정적입니다. 모든 콘텐츠 형식을 통해 일관되게하다고 생각

그러나 뷰 자체가 바로 보일 것 어떤 지원하는 HTML없이

@Html.Raw(Model.Render()) 

같은, 아니면 그냥 일반 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

응답 해 주셔서 감사합니다. 처음 두 점을 이해하는 데 어려움이 있습니다. 그 말을 다시 할 수 있겠 니? 컬렉션 하나가 아니라 하나의 게시물 만 표시 하시겠습니까? – quitstalin

+0

필자가 제시 한 답변을 업데이트했습니다. –

+0

그래, 그게 도움이되었고 나는 이론적으로이 해결책을 정말로 좋아한다. 내 프로젝트에서 어떻게 작동하는지 확인해야 할 것이다. 고마워요 – quitstalin

4

부모 개체에 "PartialViewPath"속성을 지정하고 각 자식 클래스에서 PartialViewPath 속성이 해당 게시물 유형에 대한보기의 경로를 나타내는 문자열을 반환하도록합니다.그런 다음 기본보기에,이만큼 간단하다 : 나는 비슷한했다

@foreach (var post in Model.Posts) 
{ 
    Html.RenderPartial(post.PartialViewPath) 
} 
+0

좋아. 그건 의미가 있습니다. 그것은 라인을 조금 깔끔하게하지만, 실제 출력을 오브젝트에 저장하는 것보다 훨씬 낫습니다. 그러나 foreach 루프에서 부분 렌더링은 실제로 불가능하다는 것을 나는 어딘가에서 읽었다. 이게 염려 되니? 나는 꽤 자주 이와 같은 상황이 있음을 알게된다. – quitstalin

+0

아니다. 실제로 foreach를 사용하여 목록을 열거하는 것은이 동작을 달성하는 매우 일반적인 방법이다. 아마도 모델 항목이 문자열이거나 매우 단순한 경우 Html.RenderPartial을 사용하는 것이 효율적일 수 있습니다. 그러나 실제 의사 결정을 캡슐화해야하므로이 방법이 좋습니다. –

+0

확인. 감사. 러스가 일하게 할 수 없다면 이것을 백업 답으로 사용할 것입니다. 나는 당신의 대답을 마크 업 하겠지만 분명히 그렇게하기에 충분한 평판이 없다. 방금 가입 했으니 까, 여기 에티켓을 망쳐 놓으면 사과 할께. – quitstalin

0

,이 경우/다른 문을 필요로하지만, HTML은 각각의 경우 문을위한 임베디드 피하기 위해 RenderAction을 사용합니다.

은 그래서 모델은 정의 :

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

그리고 나는를 수정할 수 있습니다 : 당신이 같은 경우 문을 사용을 통해 IEnumerable<ContentViewModel> 다음 루프의 목록을 포함

@model SearchResultViewModel

이러한 부분 뷰의 HTML은 표시되는 내용면에서 모두 다르므로

내 시나리오에서는 내용이 완전히 다릅니다.

모두 비슷한 경우 작업에서 다른보기를 출력하고 단일 RenderAction 호출을 사용할 수 있습니다.

3

이에 대한 템플릿 HTML 헬퍼를 사용할 수 있습니다

  1. Views/YourView 아래 DisplayTemplates 디렉토리를 만듭니다.
  2. 이름이 <model class name>.cshtml 인 강력한 형식의보기를 추가하십시오 (면도기를 사용하는 경우). 이 뷰는 모델을 나중에 렌더링하기 위해 호출됩니다.
    예를 들어, 템플릿이 3 개 필요합니다 : A.cshtml, B.cshtml, C.cshtml.
  3. 위에서 정의한보기로 모델을 렌더링하려면 부모보기 내부에 Html.DisplayFor()을 사용하십시오.