2012-03-23 53 views
0

爲了給你一個你應該熟悉的例子,想象你正在Asp.Net MVC中構建一個Facebook Wall頁面。在牆上,有不同類型的帖子(即狀態更新,照片,視頻,鏈接等等),它們都顯示在牆上,它們的渲染方式不同,具體取決於它們是什麼類型的帖子。在我看來,最好的方法是使用多態性,我通過Post類型進行foreach,並調用每個子類型實現的呈現方法,在Web窗體的代碼隱藏中做了這樣的事情,但我無法弄清楚如何在MVC做到這一點沒有混合的擔憂,短期如果有else塊的一個巨大的名單。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(); 
} 

我如何獲得像第二部分那樣更加可靠的東西?

回答

2

您可以使用本身基於模型的局部視圖,該模型會在暴露Render方法的界面中使用。

在您的ActionResult中,您將返回此接口的具體實例,它是要顯示的內容的正確類型。

問題是,當然,您需要使用Html.Raw或類似的東西來生成Render方法中的內容,因爲View本身內部的實際HTML是靜態的。

但隨後的視圖本身只是看起來像

@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

感謝您的回覆。我無法理解你的前兩點。你可以重新說明一下嗎?這不是隻顯示一個職位,而不是一個集合? – quitstalin 2012-03-23 01:07:33

+0

我已經更新了我的答案,希望能夠證明我的觀點。 – 2012-03-23 01:23:00

+0

是的,幫助,我真的很喜歡這個解決方案的理論。我將不得不看看它是如何在我的項目中起作用的。非常感謝 – quitstalin 2012-03-23 01:48:44

4

爲父對象指定一個屬性「PartialViewPath」,並且在每個子類中都有PartialViewPath屬性返回一個字符串,該字符串表示該類型帖子視圖的路徑。然後,在你的主視圖,它是如此簡單:

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

好的。這就說得通了。它會稍微塗抹一些線條,但比將實際輸出存儲在對象中要好很多。但是我在某個地方看到,在foreach循環中渲染部分內容真的很不方便。這是關心的嗎?我發現我經常遇到這樣的情況 – quitstalin 2012-03-23 01:18:33

+0

不是真的 - 用foreach列舉一個列表是實現這種行爲的一種非常正常的方式;如果你的模型項只是一個字符串或者非常簡單的東西,那麼你可能會使用Html.RenderPartial。但是由於你需要封裝實際的決策,這種方法很好。 – 2012-03-23 01:29:35

+0

好的。謝謝。如果我無法讓Russ的工作,我將使用此作爲備用答案。我會標記你的答案,但顯然我沒有足夠的聲譽來這樣做。我剛加入,所以我很抱歉,如果我搞砸了禮儀 – quitstalin 2012-03-23 01:53:23

0

我做了類似的事情,它需要if/else語句,但使用的RenderAction,以避免在HTML內嵌每個if語句。

所以我有一個模型中定義:

@model SearchResultViewModel

其中包含通過使用if語句的IEnumerable<ContentViewModel>然後循環列表,就像你有:

@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調用。

3

你可以使用模板HTML傭工此:

  1. Views/YourView下創建一個DisplayTemplates目錄。
  2. 添加一個名稱爲<model class name>.cshtml(如果您使用剃刀)的強類型視圖。這個視圖將被調用以稍後渲染你的模型。
    對於您的示例,您需要3個模板:A.cshtml, B.cshtml, C.cshtml
  3. 要使用上述視圖渲染模型,請在父視圖內使用Html.DisplayFor()