จุดประสงค์ของบทความนี้คือการสร้างเมนูที่ดูลื่นและใช้งานง่ายสำหรับเว็บไซต์ที่เปิดใช้งาน ASP.NET เพื่อให้บรรลุเป้าหมายนี้เราจะใช้ฟังก์ชั่นมาตรฐานของการควบคุมเว็บเมนู ASP.NET และปรับปรุงรูปลักษณ์อย่างหมดจดโดยใช้แผ่นสไตล์ cascading (CSS)
สำหรับคนที่คุณคุ้นเคยกับ CSS ชื่อของบทความนี้จะส่งเสียงระฆังอย่างแน่นอน CSS ที่ใช้เพื่อปรับปรุงรูปลักษณ์และความรู้สึกของการควบคุมเมนู ASP.NET นั้นถูกลบล้างในบทความที่รู้จักกันอย่างแพร่หลายในรายการแยกออกจากกันชื่อ "ประตูบานเลื่อนของ CSS"
CSS ที่ใช้ในการปรับปรุงรูปลักษณ์และความรู้สึกของเมนูนั้นอธิบายไว้อย่างละเอียดในบทความในรายการแยกออกจากกัน เครดิตเมื่อเครดิตถึงกำหนด ขอบคุณ Douglas Bowman ที่มอบ CSS ให้เรา อย่าลืมอ่านบทความของเขาก่อนหากคุณไม่คุ้นเคย
จุดเน้นของบทความนี้คือวิธีการจำลองเมนูดังกล่าวในสภาพแวดล้อม ASP.NET มาเริ่มกันเถอะ ...
มายิง Visual Studio 2008 และสร้างโครงการใหม่โดยใช้เทมเพลตโครงการ ASP.NET Web Application Project เทมเพลตนี้จะเพิ่มแบบฟอร์มเว็บเริ่มต้นโดยอัตโนมัติชื่อ "default.aspx" โดยอัตโนมัติ เปิดในตัวแก้ไขและเพิ่มการควบคุมเมนูจากกล่องเครื่องมือซึ่งคุณสามารถค้นหาได้ภายใต้แท็บการนำทาง หากคุณเรียกใช้เว็บไซต์ตอนนี้คุณจะต้องจ้องมองที่หน้าว่าง สำหรับเมนูที่จะแสดงสิ่งที่มันต้องผูกพันกับข้อมูลบางอย่าง
วิธีที่ง่ายที่สุดในการกำหนดข้อมูลสำหรับการควบคุมเมนูที่จะใช้และเปิดใช้งานผู้เข้าชมเพื่อนำทางผ่านเว็บไซต์คือการเชื่อมโยงกับแผนที่ไซต์ เพิ่มรายการแผนที่ไซต์ใหม่ในโครงการโดยใช้ชื่อที่เสนอของ "Web.Sitemap" แผนที่ไซต์เป็นไฟล์ XML ที่จัดระเบียบหน้าของไซต์ในลักษณะลำดับชั้น ข้อได้เปรียบที่เพิ่มขึ้นคือมีการอ้างอิงโดยอัตโนมัติโดยการควบคุม SiteMapDataSource
ถัดไปเพิ่มบางหน้าลงใน SiteMap ตามที่แสดงในรายการด้านล่าง
รายการ 1 - web.sitemap
<? xml version = " 1.0 " encoding = " utf-8 " ?>
< siteMap xmlns = " http://schemas.microsoft.com/AspNet/SiteMap-File-1.0 " >
< siteMapNode url = " " title = " " description = " " >
< siteMapNode url = " Default.aspx " title = " Home " description = " Take me back to the dasboard " />
< siteMapNode url = " Products.aspx " title = " Products " description = " Browse our catalog " />
< siteMapNode url = " Download.aspx " title = " Download " description = " Download neat stuff " />
< siteMapNode url = " Forum.aspx " title = " Forum " description = " Ask questions on our forum " />
< siteMapNode url = " Contact.aspx " title = " Contact " description = " Contact us " />
</ siteMapNode >
</ siteMap >ตอนนี้เพิ่มการควบคุม SiteMapDataSource ลงในหน้าและตั้งค่าคุณสมบัติ DataSourceId ของการควบคุมเมนูเป็น ID ของแหล่งข้อมูล ตั้งค่าคุณสมบัติการวางแนวของการควบคุมเมนูเป็นแนวนอนเนื่องจากค่าเริ่มต้นเป็นแนวตั้ง สุดท้าย แต่ไม่น้อยที่สุดตั้งค่าคุณสมบัติ showstartingNode ของ siteMapDataSource เป็นเท็จ หากคุณไม่ทำเช่นนี้เฉพาะโหนดรูทจะปรากฏขึ้นและเราไม่ต้องการรวมโหนดฐานนี้ไว้ในเมนู รหัสของคุณควรมีลักษณะคล้ายกับรหัสที่แสดงในรายการ 2
รายการ 2 - default.aspx
< asp:Menu
ID =" Menu1 "
runat =" server "
DataSourceID =" SitemapDataSource1 "
Orientation =" Horizontal "
> </ asp:Menu >
< asp:SiteMapDataSource
ID =" SiteMapDataSource1 "
runat =" server "
ShowStartingNode =" False "
/>หากคุณดูหน้าในเบราว์เซอร์ตอนนี้คุณควรเห็นเมนูที่ใช้งานได้ แต่น่าเบื่อ
รูปที่ 1 - เมนูแนวนอนธรรมดา

ก่อนที่เราจะเริ่มใช้ CSS กับเมนูมีปัญหาอื่นที่ต้องได้รับการแก้ไขก่อน หากคุณดูที่รหัส HTML ที่เกิดขึ้นซึ่งสร้างขึ้นเมื่อคุณขอหน้าค่าเริ่มต้น. ASPX คุณจะสังเกตเห็นว่าการควบคุมเมนูไม่ได้สร้างรหัส HTML ที่ยืดหยุ่นที่สุด โดยค่าเริ่มต้นจะห่อแต่ละรายการเมนูในตาราง สิ่งนี้ไม่ได้ให้ยืมตัวเองใช้ CSS ได้อย่างง่ายดาย มันจะดีกว่าถ้าเมนูควบคุมสร้างรายการ Unordererd ซึ่งมีรายการเมนูทั้งหมด
โชคดีที่ HTML ที่สร้างขึ้นสามารถปรับได้โดยใช้อะแดปเตอร์ควบคุม อะแดปเตอร์ควบคุมช่วยให้คุณแสดง HTML ที่คุณต้องการ โชคดีที่อะแดปเตอร์ควบคุมดังกล่าวพร้อมใช้งานใน CodePlex ชุดอะแดปเตอร์ควบคุมที่เป็นมิตรของ CSS ให้อะแดปเตอร์ควบคุมที่สร้างไว้ล่วงหน้ารวมถึงชุดใหม่สำหรับการควบคุมเมนู ASP.NET
ในการใช้อะแดปเตอร์ควบคุมที่เป็นมิตร CSS ทำตามขั้นตอนเหล่านี้:
มีความจำเป็นที่จะต้องใช้ซอร์สโค้ดและรวบรวม CSSFiferly.dll Assembly ตัวเราเองเพราะเราจำเป็นต้องปรับแต่ง CSS บางส่วนที่ใช้โดยอะแดปเตอร์ในภายหลังในบทความนี้
เมื่อเพิ่มโครงการ CSSFriendly ลงในโซลูชันของคุณตัวช่วยสร้าง Visual Studio Conversion จะป๊อปอัพ เพียงแค่ดำเนินการแปลงทุกอย่างควรเป็นไปอย่างราบรื่น เมื่อการแปลงเสร็จสิ้นสิ่งที่เหลืออยู่ทั้งหมดคือการเพิ่มการอ้างอิงไปยังโครงการ CSSFriendly จากโครงการเว็บไซต์ ASP.NET
เพียงเรียกใช้เว็บไซต์และดูรหัส HTML ที่สร้างขึ้นทันที
รายการ 3 - รหัส HTML ที่เป็นมิตร CSS
< div class =" AspNet-Menu-Horizontal " id =" Menu1 " >
< ul class =" AspNet-Menu " >
< li class =" AspNet-Menu-Leaf AspNet-Menu-Selected " >
< a
href =" /Default.aspx "
class =" AspNet-Menu-Link AspNet-Menu-Selected "
title =" Take me back to the dasboard "
> Home </ a
>
</ li >
< li class =" AspNet-Menu-Leaf " >
< a
href =" /Products.aspx "
class =" AspNet-Menu-Link "
title =" Browse our catalog "
> Products </ a
>
</ li >
< li class =" AspNet-Menu-Leaf " >
< a
href =" /Download.aspx "
class =" AspNet-Menu-Link "
title =" Download neat stuff "
> Download </ a
>
</ li >
< li class =" AspNet-Menu-Leaf " >
< a
href =" /Forum.aspx "
class =" AspNet-Menu-Link "
title =" Ask questions on our forum "
> Forum </ a
>
</ li >
< li class =" AspNet-Menu-Leaf " >
< a href =" /Contact.aspx " class =" AspNet-Menu-Link " title =" Contact us "
> Contact </ a
>
</ li >
</ ul >
</ div >สิ่งต่างๆกำลังมองหาตอนนี้
หมายเหตุ : ไฟล์ CSSFiferLyAdapters.Browser ช่วยให้คุณสามารถระบุอะแดปเตอร์ควบคุมที่เป็นมิตร CSS ที่ควรใช้ ฉันทำ habbit ในการแสดงความคิดเห็นอะแดปเตอร์ทั้งหมดยกเว้นสิ่งที่ฉันต้องการใช้ วิธีนี้ไม่มีการควบคุมอื่น ๆ ที่ "ปรับ" และพวกเขาจะสร้าง HTML เริ่มต้น
อย่างที่คุณเห็นจากรหัสที่แสดงในรายการด้านบนอะแดปเตอร์สำหรับการควบคุมเมนูจะฉีดคลาส CSS ที่จำเป็นโดยอัตโนมัติสำหรับ <ul> , <li> และ <a> แท็ก สิ่งนี้ช่วยให้เราเข้าใจปัญหาจากการกำหนดสิ่งเหล่านี้
นอกจากนี้ยังเป็นเรื่องธรรมดาสำหรับหน้าเดียวที่จะมีมากกว่าตัวควบคุมอะแดปเตอร์เดียวเช่นเมนู หากคุณต้องการรูปลักษณ์และความรู้สึกที่แตกต่างกันสำหรับการควบคุมแต่ละครั้งให้ตั้งค่า CSSSelectorClass สำหรับการควบคุมที่ดัดแปลง ตัวอย่างเช่นคุณอาจตั้งค่าของคุณสมบัติ CSSSelectorClass ดังนี้:
รายการ 4 - คุณสมบัติ CSSSelectorClass
< asp:Menu
ID =" Menu1 "
runat =" server "
DataSourceID =" SitemapDataSource1 "
Orientation =" Horizontal "
CssSelectorClass =" PrettyMenu "
> </ asp:Menu > ผลที่ได้คือรหัส HTML ที่สร้างขึ้นโดยตัวควบคุมที่ดัดแปลงจะอยู่ในเลเยอร์ใหม่ ( <div> )
รายการ 5 - ห่อรหัส HTML ที่สร้างขึ้น
< div class =" PrettyMenu " id =" Menu1 " >
<!-- Other HTML code -->
</ div >โปรดทราบว่าคุณสมบัตินี้มีความเฉพาะเจาะจงกับอะแดปเตอร์ที่เป็นมิตร CSS มันเป็นแอตทริบิวต์ที่กำหนดเอง (expando) ซึ่งคุณสามารถตั้งค่าสำหรับการควบคุมที่รองรับโดยไลบรารีนี้ คุณต้องการข้อมูลเพิ่มเติมเกี่ยวกับวิธีการทำงานของอะแดปเตอร์ที่เป็นมิตรจากนั้นโปรดศึกษาลิงค์ต่อไปนี้:
ด้วย CSSSelectorClass ที่สร้างเลเยอร์แยกต่างหาก ( <div> ) รอบ ๆ เมนูและคลาส CSS ที่ฉีดโดยอัตโนมัติในสถานที่ที่เราพร้อมที่จะเริ่มจัดแต่งทรงผม
CSS ที่ใช้นั้นเป็นแบบจำลองของบทความ A APART ดังที่ได้กล่าวไว้ก่อนการมุ่งเน้นของบทความนี้ไม่ได้อยู่ในโครงสร้างของ CSS แต่เป็นวิธีการใช้กับการควบคุมเมนู ASP.NET เพื่อให้ได้เมนูตารางที่ดูเรียบร้อย ผลลัพธ์ที่เสร็จแล้วสามารถดูได้ในรูปที่ 2
รูปที่ 2 - ผลลัพธ์ที่เสร็จแล้ว

ในหน้าดาวน์โหลดคุณสามารถค้นหาซอร์สโค้ดสำหรับบทความนี้ มันมีแผ่นสไตล์และภาพที่จำเป็น เพียงทำตามขั้นตอนต่อไปนี้เพื่อสร้างผลลัพธ์ที่เสร็จแล้ว:
<Pages> โหนดเป็นค่าเริ่มต้น (ดูรายการ 6)รายการ 6 - Web.config ข้อความที่ตัดตอนมา
< system .web>
<!-- ... -->
< pages theme = " Default " >
<!-- ... -->
</ pages >
<!-- ... -->
</ system .web>CSS ที่ใช้ในการแก้ปัญหาของฉันเป็นแบบจำลองของบทความในรายการแยกออกจากกัน แต่มีการเปลี่ยนแปลงบางอย่าง การเปลี่ยนแปลงส่วนใหญ่มีความสัมพันธ์กับโครงสร้าง CSS ที่ใช้โดยอะแดปเตอร์ที่เป็นมิตร CSS
เพื่อที่จะใช้ CSS โครงสร้างที่ถูกต้องจำเป็นต้องใช้ เมื่อจัดแต่งทรงผมที่มีการปรับ HTML โดยอะแดปเตอร์ที่เป็นมิตรฉันพบว่ามีประโยชน์ในการใช้ไดอะแกรมที่กล่าวถึงในกระดาษสีขาว ไดอะแกรมเหล่านี้แสดงให้คุณเห็นอย่างชัดเจนว่า CSS มีโครงสร้างอย่างไร
คุณสามารถค้นหาไดอะแกรมสำหรับการควบคุมเมนูได้ที่นี่
คำถามหนึ่งที่ฉันมักจะเกิดขึ้นในฟอรัมจำนวนมากคือวิธีการใช้เมนูย่อยแนวนอนซึ่งเปลี่ยนแปลงเมื่อผู้ใช้เลือกแท็บอื่นจากเมนูระดับบนสุด ในการสร้างสิ่งนี้ก่อนอื่นเราต้องปรับแผนที่ไซต์ของเรา
รายการ 7 แสดงแผนที่ไซต์ที่ปรับแล้ว
รายการ 7 - web.sitemap พร้อม "รายการเมนูย่อย"
<? xml version = " 1.0 " encoding = " utf-8 " ?>
< siteMap xmlns = " http://schemas.microsoft.com/AspNet/SiteMap-File-1.0 " >
< siteMapNode url = " " title = " " description = " " >
< siteMapNode url = " Default.aspx " title = " Home " description = " Take me back to the dasboard " >
< siteMapNode url = " About.aspx " title = " About us " description = " " />
< siteMapNode url = " Foo.aspx " title = " Foo " description = " " />
< siteMapNode url = " Bar.aspx " title = " Bar " description = " " />
</ siteMapNode >
<!-- ... -->
</ siteMap >เพื่อประโยชน์ของ Brevity 7 แสดงเฉพาะรายการเมนูย่อย (โหนด) สำหรับโหนดหน้าแรก ตรวจสอบ web.sitemap ในซอร์สโค้ดสำหรับเวอร์ชันที่สมบูรณ์ ตอนนี้เมื่อคุณเรียกดูเว็บไซต์โดยใช้แผนที่ไซต์นี้คุณจะเห็นเอฟเฟกต์ที่แสดงในรูปที่ 3
รูปที่ 3 - รายการเมนูย่อย

ในการปิดการใช้งานเอฟเฟกต์นี้ตั้งค่าคุณสมบัติ MaximumDynamicDisplaylevels ของการควบคุมเมนูเป็นศูนย์ดังแสดงในรายการ 8
รายการ 8 - คุณสมบัติสูงสุด
< asp:Menu
ID =" Menu1 "
runat =" server "
DataSourceID =" SitemapDataSource1 "
Orientation =" Horizontal "
CssSelectorClass =" PrettyMenu "
MaximumDynamicDisplayLevels =" 0 "
> </ asp:Menu >ถัดไปเพิ่มเมนูที่สองและการควบคุม sitemapdatasource และตั้งค่าคุณสมบัติของพวกเขาดังแสดงในรายการ 9
รายการ 9 - การควบคุมเมนูย่อย
< asp:Menu
ID =" Menu1 "
runat =" server "
DataSourceID =" SitemapDataSource1 "
Orientation =" Horizontal "
CssSelectorClass =" PrettyMenu "
MaximumDynamicDisplayLevels =" 0 "
>
</ asp:Menu >
< asp:Menu
ID =" Menu2 "
runat =" server "
DataSourceID =" SitemapDataSource2 "
Orientation =" Horizontal "
CssSelectorClass =" PrettySubMenu "
>
</ asp:Menu >
< asp:SiteMapDataSource
ID =" SiteMapDataSource1 "
runat =" server "
ShowStartingNode =" False "
/>
< asp:SiteMapDataSource
ID =" SiteMapDataSource2 "
runat =" server "
StartingNodeOffset =" 1 "
ShowStartingNode =" False "
/>โดยทั่วไปเราบอกเมนูที่สองว่าควรแสดงระดับที่สองของโหนดที่พบในแผนที่ไซต์และไม่ควรแสดงโหนดเริ่มต้นซึ่งสอดคล้องกับแท็บที่เลือกของเมนูแรก
นอกจากนี้ CSSSelectorClass สำหรับเมนูที่สองถูกตั้งค่าเป็น PrettySubMenu CSS สำหรับเมนูนี้มีลักษณะคล้ายกับเมนูแรก ดาวน์โหลดซอร์สโค้ดหากคุณต้องการตรวจสอบ การรันเว็บไซต์ตอนนี้จะให้ผลลัพธ์ที่น่ากลัวนี้แก่คุณ
รูปที่ 4 - รายการเมนูย่อยสไตล์

ปัญหาสุดท้ายหนึ่งจะต้องได้รับการแก้ไข เพื่อแสดงให้เห็นถึงปัญหานี้โครงการจะต้องจัดระเบียบใหม่
ก่อนอื่นเรามาเพิ่มหน้าหลักในโครงการที่เรียกว่า site.master ย้ายรหัสเมนูและแหล่งข้อมูลจากหน้า default.aspx ไปยังหน้าหลักและวางไว้ก่อนที่ตัวยึดเนื้อหาแรกในร่างกาย หลังจากนั้นคุณสามารถลบหน้า default.aspx ได้อย่างปลอดภัย
ตอนนี้เรามาเพิ่มรายการฟอร์มเนื้อหาเว็บสองสามรายการลงในโครงการ เพิ่มแบบฟอร์มเนื้อหาเว็บที่สอดคล้องกับรายการของโหนดแรกของแผนที่ไซต์และโหนดย่อยคือ:
ตรวจสอบให้แน่ใจว่าได้เลือก site.master เป็นหน้าหลักสำหรับแต่ละแบบฟอร์มเนื้อหาเว็บเหล่านี้ หน้าอื่น ๆ ที่กล่าวถึงใน web.sitemap นั้นมีวัตถุประสงค์เพื่อเป็นตัวอย่างอย่างหมดจด
เปิดไซต์อีกครั้งและนำทางไปยังหน้า Foo สิ่งนี้จะเปิดเผยปัญหา
รูปที่ 5 - ปัญหาการเลือก

เนื่องจากเราได้นำทางไปยังระดับล่างในแผนที่เว็บไซต์เมนูระดับบนสุดไม่ทราบว่ารายการเมนูใดที่ควรทำเครื่องหมายตามที่เลือก เราจะต้องทำการเข้ารหัสบางอย่างในรหัสของหน้าหลักเพื่อแก้ไขปัญหานี้
รายการ 10 แสดงให้คุณเห็นถึงอาหารจานหนึ่งที่จำเป็น
รายการ 10 - การเลือกรายการเมนูระดับบนสุดที่ถูกต้อง
namespace MenuWebApplication
{
public partial class Site : System . Web . UI . MasterPage
{
private static string ExtractBaseUrl ( string url )
{
return url . Contains ( "?" ) ? url . Remove ( url . IndexOf ( '?' ) ) : url ;
}
protected void Page_Load ( object sender , EventArgs e )
{
Menu1 . DataBind ( ) ;
// Which node in the site map is currently selected?
SiteMapNode currentNode = SiteMap . CurrentNode ;
if ( currentNode != null )
{
// Obtain the Url of the currently selected node's parent node.
string parentUrl = String . Empty ;
SiteMapNode parentNode = currentNode . ParentNode ;
if ( parentNode != null )
{
parentUrl = ExtractBaseUrl ( parentNode . Url ) ;
}
// Obtain the Url of the currently selected node.
string currentUrl = ExtractBaseUrl ( currentNode . Url ) ;
// Iterate the top level menu tier.
foreach ( MenuItem menuItem in Menu1 . Items )
{
// Compare the menu item's Url against the currently
// selected node's Url or the Url of its parent.
string menuItemUrl = ExtractBaseUrl ( menuItem . NavigateUrl ) ;
if ( ( currentUrl == menuItemUrl ) || ( parentUrl == menuItemUrl ) )
{
// If either matches then mark the top level menu item as selected.
Menu1 . Items [ Menu1 . Items . IndexOf ( menuItem ) ] . Selected = true ;
break ;
}
}
}
}
}
}ตอนนี้คุณมีอิสระที่จะเลือกรายการเมนูย่อยใด ๆ รายการเมนูระดับบนสุดที่สอดคล้องกันจะยังคงได้รับการคัดเลือกเพื่อให้เบาะแสภาพแก่ผู้เข้าชมว่าเขาอยู่ที่ไหนในเว็บไซต์
รูปที่ 6 - แก้ไขปัญหาการเลือก

มันค่อนข้างทำงานเล็กน้อยในการสร้างเมนูตารางแฟนซีพร้อมเมนูย่อยแนวนอนที่ละเอียดอ่อนบริบท แต่ในที่สุดคุณก็จบลงด้วยเมนูที่ดูลื่นและเป็นมิตรกับผู้ใช้
ฉันขอแนะนำให้คุณใช้เมนูดังกล่าวในการควบคุมผู้ใช้และรวมการควบคุมผู้ใช้นั้นไว้ในหน้าหลักของเว็บไซต์ของคุณ ในกรณีส่วนใหญ่เมนูดังกล่าวจะถูกใช้ตลอดทั้งเว็บไซต์