網站導航(Menu 控件)


       Menu 是另一個支持層次化數據的富控件。它可以綁定到數據源(聲明性的)或編程使用 MenuItem 對象來填充。

       MenuItem 類不像 TreeNode 類那樣豐富,它不支持復選框,也不能通過編程設置它們的 折疊/展開 狀態。不過,它們也有很多相似的屬性,包括那些用於設置圖片、確定條目是否可選以及指定目標鏈接的屬性。

MenuItem 的屬性:

Text 菜單中顯示的文字
TooTip 鼠標停留菜單項時的提示文字
Value 保存不顯示的額外數據(比如某些程序需要用到的 ID)
NavigateUrl 如果設置了值,單擊節點會前進至此 Url。否則,需要響應 Menu.MenuItemClick事件確定要執行的活動
Target 它設置了鏈接的目標窗口或框架。Menu 自身也暴露了 Target 屬性設置所有的 MenuItem 實例的默認目標
Selectable 如果為 false,菜單項不可選。通常只在菜單項有一些可選的子菜單項時,才設為 false
ImageUrl 菜單項旁邊的圖片
PopOutImageUrl 菜單項包含子項時現在在菜單項旁的圖片,默認是一個小的實心箭頭
SeparatorImageUrl 菜單項下面顯示的圖片,用於分隔菜單項

 

       和遍歷 TreeView 結構的方式相同,Menu 控件僅做很小的改動,幾乎就可以重用先前 TreeView 的代碼:

protected void Page_Load(object sender, EventArgs e)
{
    if (!Page.IsPostBack)
    {
        DataSet ds = GetProductsAndCategories();
 
        foreach (DataRow row in ds.Tables["Categories"].Rows)
        {
            MenuItem itemCategory = new MenuItem(
                row["CategoryName"].ToString(),
                row["CategoryID"].ToString());
            Menu1.Items.Add(itemCategory);
 
            DataRow[] childRows = row.GetChildRows(ds.Relations["CatProds"]);
            foreach (DataRow childRow in childRows)
            {
                MenuItem itemProduct = new MenuItem(
                    childRow["ProductName"].ToString(),
                    childRow["ProductID"].ToString());
                itemCategory.ChildItems.Add(itemProduct);
            }
        }
    }
 
}
 
protected void Menu1_MenuItemClick(object sender, MenuEventArgs e)
{
    if (Menu1.SelectedItem.Depth == 0)
    {
        lblInfo.Text = "You selected Category ID: ";
    }
    else if (Menu1.SelectedItem.Depth == 1)
    {
        lblInfo.Text = "You selected Product ID: ";
    }
    lblInfo.Text += Menu1.SelectedItem.Value;
}

image

 

       雖然 Menu 和 TreeView 的呈現方式非常不同,但它們暴露了非常相似的編程模型。它們還有相似的基於樣式的格式化模型。

       不過,它們還是有一些顯著的差異:

  • Menu 每次顯示一個子菜單;TreeView 可以一次展開任意多個節點。
  • Menu 在頁面里顯示第一層的鏈接;TreeView 顯示頁面上內聯的所有項。
  • Menu 不支持按需填充及客戶端回調;TreeView 支持。
  • Menu 支持模板;TreeView 不支持。
  • Menu 支持水平和垂直布局;TreeView 只支持垂直布局。

 

 

Menu 樣式

       Menu 控件提供了數量驚人的樣式。和 TreeView 一樣,Menu 從 Style 基類派生了自定義類(實際上,它派生了 MenuStyle類 和 MenuItemStyle類)。

       這些樣式增加了間距屬性 ItemSpacing、HorizontalPadding、VerticalPadding;但不能通過樣式設置菜單項的圖片,因為它沒有 ImageUrl 屬性。

 

       Menu 在很大程度上和 TreeView 相似,它支持為位於不同層級的菜單定義不同的菜單樣式。不過,一個主要的區別是 Menu 控件鼓勵你區分靜態項(菜單剛創建時就顯示在頁面上的第一層條目)和動態項(鼠標移動到菜單某個區域時被添加的彈出的菜單項)。

       對於大多網站,這兩個元素具有明顯的區別。為了支持這些,Menu 定義了兩組平行樣式,如下:

StaticMenuStyle DynamicMenuStyle 設置總體“盒子”的外觀,所有的菜單項出現在這里
StaticMenuItemStyle DynamicMenuItemStyle 設置單個菜單項的外觀
StaticSelectedStyle DynamicSelectedStyle 設置選擇項的外觀,選擇項指的是前一個被單擊的項(且觸發上一次回發的項)
StaticHoverStyle DynamicHoverStyle 設置鼠標停留時項的外觀

       還可以設置層級特定的樣式,這樣每層的菜單和子菜單都不一樣。可通過 3 個集合來設置:LevelMenuItemStylesLevelSubMenuStylesLevelSelectedStyles。這些集合分別作用於普通的菜單項,包含其他菜單項的菜單項以及被選擇的菜單項。

       可能你會覺得不必做那么多工作區分動態樣式和靜態樣式。但考慮到 Menu 控件另一個非同尋常的功能,這一模型就很有意義:它允許設置靜態層次的數目。在默認情況下,只有一個靜態層,其他所有的項只有把鼠標停留在相應的父菜單上時才會彈出。不過,如果設置了 Menu.StaticDisplayLevels 屬性,就可改變這一切。例如,如果設為 2 ,前兩層菜單將使用靜態樣式呈現在頁面上,還可用 StaticSubMenuIdent 屬性控制每層的縮進。

       在調整特定呈現方面,Menu 控件會暴露更多頂層屬性。例如,可以設置菜單消失前的延時(DisappearAfter)、展開圖標和分隔符的默認圖片和滾動行為等。具體可以參考 Visual Studio 幫助文檔獲取屬性的完整列表。

 

 

模板

       通過 StaticMenuItemTemplate 和 DynamicMenuItemTemplate 屬性,Menu 控件也能夠支持模板。這些模板能讓你完全控制每個菜單項要呈現的 HTML。

       有趣的是,無論是以聲明的方式還是編程的方式填充 Menu 類,都能夠使用模板。從模板的角度來看,你總是綁定到 MenuItem 對象。也就是說,模板總是必須從 MenuItem.Text 屬性抓取菜單項的值,如下所示:

<asp:Menu ID="Menu1" runat="server" >
    <StaticItemTemplate>
        <%# Eval("Text") %>
    </StaticItemTemplate>
</asp:Menu>

 

       你想使用 Menu 模板功能的另一個原因可能是顯示來自數據對象的多個信息。例如,你可能希望同時在帶單項上顯示 SiteMapNode 的標題和描述。遺憾的是,這不可能。問題在於 Menu 直接綁定到 MenuItem 對象。MenuItem 確實暴露了 DataItem 屬性,但當它被添加到菜單時,DataItem 不再引用當初用來填充它的 SiteMapNode。

       如果確實非常希望這樣顯示,可以在類里寫一個基於 URL 查找 SiteMapNode 的自定義方法。這本來不是必要的工作,不過它確實能夠使菜單項模板獲得描述信息:

private string matchingDescription;
 
protected string GetDescriptionFromTitle(string title)
{
    SiteMapNode node = SiteMap.RootNode;
    SearchNodes(node, title);
    return matchingDescription;
}
 
private void SearchNodes(SiteMapNode node, string title)
{
    if (node.Title == title)
    {
        matchingDescription = node.Description;
        return;
    }
    else
    {
        foreach (SiteMapNode child in node.ChildNodes)
        {
            SearchNodes(child, title);
        }
    }
}
<asp:Menu ID="Menu1" runat="server" DataSourceID="SiteMapDataSource1" StaticDisplayLevels="2">
    <StaticItemTemplate>
        <%# Eval("Text") %><br />
        <small>
            <%# GetDescriptionFromTitle(((MenuItem)Container.DataItem).Text)%>
        </small>
    </StaticItemTemplate>
</asp:Menu>

 

       你還可以為 Menu 控件聲明一個數據綁定,它指定綁定對象中用於 MenuItem 文本的那個屬性。不過,它只接受一個字段。盡管如此,它還是可以很方便的把標題顯示為文本而把描述作為提示文本:

<asp:Menu ID="Menu1" runat="server" DataSourceID="SiteMapDataSource1" StaticDisplayLevels="2">
    <DataBindings>
        <asp:MenuItemBinding DataMember="SiteMapNode" TextField="Title" ToolTipField="Description" />
    </DataBindings>
</asp:Menu>

 

注解:

       在 ASP.NET 4 里,Menu 控件不再使用 HTML 表格來呈現自己,而是把自己呈現為一組無序的條目(使用 <ul> 和 <li> 元素),並通過樣式規則來創建正確的格式。

       Menu 控件在頁面的頂部以樣式塊的形式呈現其所有樣式,而不與呈現的 HTML 內聯。但是,可以把 Menu.IncludeStyleBlock 屬性設為 fasle 以告知 Menu 不要呈現其樣式,這樣能讓你完全控制 Menu 樣式,甚至可以采用外部樣式表的樣式。

       (如果你需要一個起點,可以先把該屬性設為 true 運行頁面,復制呈現的 HTML 樣式代碼,根據需要做調整)


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM