如何在ASP.NET Web站點中統一頁面布局[Creating a Consistent Layout in ASP.NET Web Pages(Razor) Sites]
一、布局頁面介紹[About Layout Pages]
很多網站有些內容需要顯示在各個頁面中,比如Header,Footer或者告訴用戶已經登錄的部分。ASP.NET允許你創建一個單獨的文件來包含文本、標簽和代碼的內容塊,從而搭建一個風格整齊的網站。接下來你就可以將這個內容塊插入到任何你想要讓它展示的頁面中。采用這種方法您不需要將這部分內容在各個頁面中復制粘貼。由於創建了公共內容,也使您的更新維護更加簡單。如果你需要修改這些內容,只需更新一個文件即可,這個修改操作但會反映到所有你應用了此內容的頁面。
下面展示了內容塊是如何工作的。當一個web服務器請求一個頁面時,ASP.NET便會將內容塊插入到RenderPage方法被調用的地方。最終合並的頁面就會被發送到瀏覽器。
接下來這個過程中,您將會創建一個包含兩個內容塊(一個Header和一個Footer)的頁面,這些內容塊是單獨存在在不同文件中的。您也可以在網站中的任何頁面中使用這些內容塊。操作完成之后,您將會得到一個類似效果:
- 在網站的根目錄下,創建一個名為Index.cshtml的文件。
- 用以下內容替換文件默認生成的所有內容:
1 <!DOCTYPE html> 2 <html> 3 <head> 4 <title>Main Page</title> 5 </head> 6 <body> 7 <h1>Index Page Content</h1> 8 <p>This is the content of the main page.</p> 9 </body> 10 </html>
3. 在根目錄下,創建一個Shared文件夾。
注:在Web頁面中通常將存在公共頁面文件的文件夾命名為Shared。
4. 在Shared文件夾下,創建一個_Header.cshtml視圖文件。
5. 用以下內容替換之:
<div class="header">This is header text.</div>
注意文件_Header.cshtml是以下划線(_)為前綴的。如果一個頁面的名字以下線線開頭,ASP.NET則不會將其發送到瀏覽器。從而阻止人們向這些頁面直接發起的請求。因為您並不真的希望用戶請求這些頁面—他們的存在只是作為插入到其他頁面的,所以用下划線前綴為這些內容塊頁面命名是一個很好的主意。
6. 在Shared文件夾中,創建_footer.cshtml視圖文件,並替換為以下內容:
<div class="footer">© 2012 Contoso Pharmaceuticals. All rights reserved. </div>
7. 在Index.cshtml頁面中,調用兩次RenderPage()方法,如下所示:
<!DOCTYPE html> <html> <head> <title>Main Page</title> </head> <body> @RenderPage("~/Shared/_Header.cshtml") <h1>Index Page Content</h1> <p>This is the content of the main page.</p> @RenderPage("~/Shared/_Footer.cshtml") </body> </html>
以上展示了如何在一個web頁面中添加內容塊。調用RenderPage()方法並傳入您希望插入內容的文件名。在這個示例中,您正在將_Header.cshtml和_Footer.cshtml文件中的內容插入到Index.cshtml文件中。
8. 在瀏覽器中運行Index.cshtml頁面。
9. 在瀏覽器中,查看頁面源代碼。(例如,IE中,右建->點擊查看源[View Source])。
您會看到合並了Index頁面標簽和內容塊(_Header.cshtml和_Footer.cshtml)之后,發送到瀏覽器的整個頁面。下面的示例展示了Index.cshtml渲染之后的源代碼。您添加到Index.cshtml中的RenderPage()方法調用被替換成了header和footer文件中實際內容。

<!DOCTYPE html> <html> <head> <title>Main Page</title> </head> <body> <div class="header"> This is header text. </div> <h1>Index Page Content</h1> <p>This is the content of the main page.</p> <div class="footer"> © 2012 Contoso Pharmaceuticals. All rights reserved. </div> </body> </html>
二、使用布局頁面統一風格[Creating a Consistent Look Using Layout Pages]
到目前為止,您已經看到了很容易就實現了多個頁面中包含相同內容。創建統一風格站點更具結構化的方法是使用布局頁面。一個布局頁定義了Web頁面的結構,但是並不包含任何實際內容。當您創建了一個布局頁之后,您可以編寫包含內容或聯合布局頁的Web頁面(?)。這些頁面也會按布局頁統一格式化顯示。(在這個意義上,布局頁實際是利用定義在其他頁面中的內容提供一種模板。)
這種布局頁除了包含對RenderBody()方法的調用,就像大多數HTML頁面。布局頁面中RenderBody()方法的位置確定了將來包含內容頁面中信息的位置。
下圖展示了運行的時候內容頁面和布局頁面是如何合並,並生成最終頁面的。瀏覽器請求內容頁時,內容頁有代碼聲明了其應用的布局頁面,並應用該布局頁面的結構。在布局頁面中,內容頁的信息都會插入到RenderBody方法調用的位置。通過調用RenderPage()方法,內容塊也可以插入到布局頁面中,就像上一節中的示例一樣。
接下來演示如何創建一個布局頁並將內容頁整合進去。
- 在Shared文件夾下創建一個_Layout1.cshtml的文件。
- 用以下代碼替換其中所有內容:
<!DOCTYPE html> <html> <head> <title>Structured Content </title> <link href="~/Styles/Site.css" rel="stylesheet" type="text/css" /> </head> <body> @RenderPage("~/Shared/_Header2.cshtml") <div id="main"> @RenderBody() </div> <div id="footer"> © 2012 Contoso Pharmaceuticals. All rights reserved. </div> </body> </html>
在布局頁面中使用RenderPage()方法插入內容塊。一個布局頁面只能包含調用一次RenderBody()方法。
- 在Shared文件夾下,創建一個_Header2.cshtml的文件並用以下內容替換之:
<div id="header">Creating a Consistent Look</div>
- 在根目錄下,創建一個Styles文件夾。
- 在Styles文件夾下,創建Site.css文件並添加以下樣式定義:
h1 { border-bottom: 3px solid #cc9900; font: 2.75em/1.75em Georgia, serif; color: #996600; } ul { list-style-type: none; } body { margin: 0; padding: 1em; background-color: #ffffff; font: 75%/1.75em "Trebuchet MS", Verdana, sans-serif; color: #006600; } #list { margin: 1em 0 7em -3em; padding: 1em 0 0 0; background-color: #ffffff; color: #996600; width: 25%; float: left; } #header, #footer { margin: 0; padding: 0; color: #996600; }
- 在根目錄下,創建Content1.cshtml文件並用以下內容替換:
@{ Layout = "~/Shared/_Layout1.cshtml"; } <h1> Structured Content </h1> <p>Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.</p>
這就是一個應用了布局頁面的頁面。頁面頂部的代碼塊指示了將應用哪一個布局頁面來格式化這些內容。
- 在瀏覽器中運行Content1.cshtml,這個渲染的頁面使用了定義在_Layout1.cshtml的格式、樣式表和定義在Content1.cshtml中的文本(內容)。
您還可以重覆第6步創建共享了相同布局頁面的內容頁面。
三、設計包含多個內容部分的布局頁面[Designing Layout Pages That Have Multiple Content Sections]
一個內容頁面可以包含多個部分,這對於希望使用有可替換內容的多塊區域布局是非常有用的。在這樣的內容頁面中,為每一部分單獨命名,名稱不能重復。在這個布局頁面中,添加RenderBody()方法指定未命名(默認部分就是未命名)的部分出現。接下來添加RenderSection()方法來單獨渲染已命名的部分。
接下來展示ASP.NET如何處理分割成多部分的內容。內容頁面中所有已命名的部分包含在一個部分塊中。(如下面示例中被命名為Header和List。)框架會在布局頁面中調用RenderSection()方法的地方插入內容部分。正如前面所見,未命名(默認)部分會插入到調用RenderBody()方法的位置。
接下來示范如何創建一個包含多內容部分的內容頁面,以及如何使用支持多內容部分的布局頁面渲染它。
- 在Shared文件夾中,創建_Layout2.cshtml文件
- 用以下內容替換生成的所有內容:
<!DOCTYPE html> <html> <head> <title>Multisection Content</title> <link href="~/Styles/Site.css" rel="stylesheet" type="text/css" /> </head> <body> <div id="header"> @RenderSection("header") </div> <div id="list"> @RenderSection("list") </div> <div id="main"> @RenderBody() </div> <div id="footer"> © 2012 Contoso Pharmaceuticals. All rights reserved. </div> </body> </html>
使用RenderSection()方法可同時渲染header和list部分。
- 在根目錄下創建Content.cshtml文件並用以下內容替換:
@{ Layout = "~/Shared/_Layout2.cshtml"; } @section header { <div id="header"> Creating a Consistent Look </div> } @section list { <ul> <li>Lorem</li> <li>Ipsum</li> <li>Dolor</li> <li>Consecte</li> <li>Eiusmod</li> <li>Tempor</li> <li>Incididu</li> </ul> } <h1>Multisection Content</h1> <p>Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.</p>
這個內容頁面包含了頁面頂部的代碼塊。所有命名部分都被包含在一個部分塊中。頁面其余的包含默認(未命名)的內容部分。
- 在瀏覽器中運行Content2.cshtml。
四、使用內容部分可選參數[Making Content Sections Optional]
通常,您在一個內容頁面中創建的部分必須完全匹配在布局頁面中定義的部分。只要下列任一條件發生,您都將得到一個錯誤:
l 內容頁面中包含一個在布局頁面中無相應部分的部分。
l 布局頁面中包含一個部分,但是沒有內容。
l 布局頁面中包含嘗試將同一部分渲染超過一次的方法調用。
然而,您可以在布局頁面中為命名部分申明為可選來重寫這些行為。從來使您定義多個共享同一布局頁面的內容頁,且它為一個具體部分可以也可不用提供內容。
- 打開Content2.cshtml文件並刪除以下部分:
@section header { <div id="header"> Creating a Consistent Look </div> }
2. 保存頁面並在瀏覽器中運行。因為內容頁面沒有為已命名的header部分提供內容部分。
3. 在Shared文件夾中,打開_Layout2.cshtml頁面並替換掉以下內容:
@RenderSection("header")
使用以下代碼:
@RenderSection("header", required: false)
使用為替代,也可以使用以下代碼塊替換,產生相同的結果:
@if (IsSectionDefined("header")) {
@RenderSection("header")
}
4. 在瀏覽器中再次運行Content2.cshtml.這次即使頁面沒有header,依然會正確顯示。
五、布局頁面傳值[Passing Data to Layout Pages]
您可能會在內容頁面中定義一系列數據,需要傳遞到布局頁面中。如果是這樣,您就需要從內容頁面傳遞這些數據到布局頁面中。例如,您可能希望顯示用戶的登錄狀態,又或者希望基於用戶輸入顯示或隱藏內容塊。
為了能傳遞數據,您可以將值放進內容頁面的PageData屬性。PageData屬性是一個你希望在頁面之間保存數據的鍵/值對集合。在布局頁面中,您可以讀出PageData屬性的值。
這里是另一個示例圖。它展示了ASP.NET如何從內容頁面到布局頁面,使用PageData屬性傳遞值。當ASP.NET開始構建Web頁面時,他會創建這個PageData集合。內容頁面中,您可能通過代碼向PageData集合添加數據。在添加的內容頁面和其他部分都可以訪問PageData集合中的值。
接下來的程序展示了如何在內容頁面和布局頁面之間傳值。當頁面運行的時候,會顯示一個讓用戶隱藏或顯示一個在布局頁面中定義的列表。當用戶點擊按鈕,會給PageData屬性設置一個true/false(Boolean)值。布局頁面讀取到值后,判斷如果為false就隱藏列表。這個值也會在內容頁面中使用,因為它能確定顯示Hide List按鈕還是Show List按鈕。
- 在根目錄下,創建文件Content3.cshtml,並替換為以下內容:
@{ Layout = "~/Shared/_Layout3.cshtml"; PageData["Title"] = "Passing Data"; PageData["ShowList"] = true; if (IsPost) { if (Request.Form["list"] == "off") { PageData["ShowList"] = false; } } } @section header { <div id="header"> Creating a Consistent Look </div> } <h1>@PageData["Title"]</h1> <p>Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.</p> @if (PageData["ShowList"] == true) { <form method="post" action=""> <input type="hidden" name="list" value="off" /> <input type="submit" value="Hide List" /> </form> } else { <form method="post" action=""> <input type="hidden" name="list" value="on" /> <input type="submit" value="Show List" /> </form> }
PageData屬性中數據儲存為了兩部分—Web頁面的標題和確定是否顯示列表的值(true/false)。
注意ASP.NET允許您通過條件代碼塊向頁面添加HTML標簽。例如,頁面body中if/else塊確定哪一個表單展示,if/else又是取決於PageData[“ShowList”]是否設置為true。
- 在Shared文件夾下,創建文件_Layout3.cshtml並用以下代碼替換:

<!DOCTYPE html> <html> <head> <title>@PageData["Title"]</title> <link href="~/Styles/Site.css" rel="stylesheet" type="text/css" /> </head> <body> <div id="header"> @RenderSection("header") </div> @if (PageData["ShowList"] == true) { <div id="list"> @RenderPage("~/Shared/_List.cshtml") </div> } <div id="main"> @RenderBody() </div> <div id="footer"> <p>© 2012 Contoso Pharmaceuticals. All rights reserved.</p> </div> </body> </html>
3. 在Shared文件夾下,創建_List.cshtml文件,並用以下內容替換:

<ul> <li>Lorem</li> <li>Ipsum</li> <li>Dolor</li> <li>Consecte</li> <li>Eiusmod</li> <li>Tempor</li> <li>Incididu</li> </ul>
4. 在瀏覽器中運行Content3.cshtml。列表在頁面左邊,Hide List按鈕在底部展示。
5. 點擊Hide List,列表會消失同時按鈕會變成Show List。
6. 點擊Show List按鈕,列表再次出現。
原文鏈接:http://www.asp.net/web-pages/overview/ui,-layouts,-and-themes/3-creating-a-consistent-look