网站导航(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 定义了两组平行样式,如下:

StaticMenuStyleDynamicMenuStyle设置总体“盒子”的外观,所有的菜单项出现在这里
StaticMenuItemStyleDynamicMenuItemStyle设置单个菜单项的外观
StaticSelectedStyleDynamicSelectedStyle设置选择项的外观,选择项指的是前一个被单击的项(且触发上一次回发的项)
StaticHoverStyleDynamicHoverStyle设置鼠标停留时项的外观

       还可以设置层级特定的样式,这样每层的菜单和子菜单都不一样。可通过 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()%>
        </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 样式代码,根据需要做调整)

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值