asp.net自带的菜单控件采用的table和javascript,导致生成的大量的html,同时在很多浏览器中都无法显示出子菜单,也只能在IE中能显示出来。
本文介绍的菜单控件采用的css 和ul list来显示菜单,生成的html小,无需javascript支持,对大部分的浏览器都支持,除ie6要单独修改css也可以使其支持。
通过本文可以了解asp.net 控件的开发,及Composite设计模式的实际运用。
采用Composite设计模式设计菜单类:
MenuCompositeitem类
namespace
Ruinet.Controls
{
[Serializable()]
public
class
MenuCompositeItem
{
private
List
<
MenuCompositeItem
>
_children
=
new
List
<
MenuCompositeItem
>
();
private
string
_text;
private
string
_link;
private
string
_target;
///
<summary>
///
菜单项
///
</summary>
///
<param name="text">
菜单名
</param>
///
<param name="link">
链接
</param>
public
MenuCompositeItem(
string
text,
string
link)
{
this
._text
=
text;
this
._link
=
link;
}
///
<summary>
///
菜单项
///
</summary>
///
<param name="text">
菜单名
</param>
///
<param name="link">
链接
</param>
///
<param name="target">
跳转目标
</param>
public
MenuCompositeItem(
string
text,
string
link,
string
target)
{
this
._text
=
text;
this
._link
=
link;
this
._target
=
target;
}
///
<summary>
///
设置或获取菜单名
///
</summary>
public
string
Text
{
get
{
return
_text; }
set
{ _text
=
value; }
}
///
<summary>
///
设置或获取链接
///
</summary>
public
string
Link
{
get
{
return
_link; }
set
{ _link
=
value; }
}
///
<summary>
///
跳转目标
///
</summary>
public
string
Target
{
get
{
return
_target; }
set
{ _target
=
value; }
}
///
<summary>
///
设置或获取子菜单
///
</summary>
public
List
<
MenuCompositeItem
>
Children
{
get
{
return
_children; }
set
{ _children
=
value; }
}
}
MenuComposite类
namespace
Ruinet.Controls
{
[DefaultProperty(
"
Menu
"
)]
[ToolboxData(
"
<{0}:MenuComposite runat=server></{0}:MenuComposite>
"
)]
public
class
MenuComposite : WebControl
{
///
<summary>
///
设置获取选择的菜单
///
</summary>
[Bindable(
true
)]
[DefaultValue(
""
)]
[Localizable(
true
)]
public
string
SelectedMenuText
{
get
{
String s
=
(String)ViewState[
"
SelectedMenuText
"
];
return
((s
==
null
)
?
String.Empty : s);
}
set
{
ViewState[
"
SelectedMenuText
"
]
=
value;
}
}
///
<summary>
///
获取和设置菜单项从ViewState
///
</summary>
[Bindable(
true
)]
[DefaultValue(
null
)]
[Localizable(
true
)]
public
MenuCompositeItem MenuItems
{
get
{
return
ViewState[
"
MenuItems
"
]
as
MenuCompositeItem;
}
set
{
ViewState[
"
MenuItems
"
]
=
value;
}
}
///
<summary>
///
呈现菜单结构
///
</summary>
///
<param name="output">
HTML输出流
</param>
protected
override
void
RenderContents(HtmlTextWriter output)
{
MenuCompositeItem root
=
this
.MenuItems;
output.Write(
@"
<div class=""navmenu"">
"
);
output.Write(
@"
<ul>
"
);
for
(
int
i
=
0
; i
<
root.Children.Count; i
++
)
{
RecursiveRender(output, root.Children[i]);
}
output.Write(
@"
</ul>
"
);
output.Write(
@"
</div>
"
);
}
///
<summary>
///
递归输出菜单项
///
</summary>
///
<param name="output">
HTML输出流
</param>
///
<param name="item">
菜单项.
</param>
///
<param name="depth">
Indentation depth.
</param>
private
void
RecursiveRender(HtmlTextWriter output, MenuCompositeItem item)
{
output.Write(
"
<li>
"
);
if
(
string
.IsNullOrEmpty(item.Target))
//
为空不设置跳转目标
{
output.Write(
@"
<a href=""
"
+
item.Link
+
@"
"">
"
);
}
else
{
output.Write(
@"
<a href=""
"
+
item.Link
+
@"
"" target= ""
"
+
item.Target
+
@"
"">
"
);
}
if
(item.Text
==
SelectedMenuText)
//
选中的菜单
{
output.Write(
@"
<span class=""selected"">
"
);
output.WriteLine(item.Text);
output.WriteLine(
"
</span>
"
);
}
else
{
output.Write(item.Text);
}
output.Write(
"
</a>
"
);
if
(item.Children.Count
>
0
)
{
output.WriteLine();
output.Write(
"
<ul>
"
);
for
(
int
i
=
0
; i
<
item.Children.Count; i
++
)
{
RecursiveRender(output, item.Children[i]);
}
output.Write(
"
</ul>
"
);
}
output.Write(
"
</li>
"
);
}
}
}
在页面中使用
添加对控件的引用后就可以直接在“工具箱”-》Controls组件中 看到MenuComposite组件
再就可以像其他asp.net 控件一样使用
使用:
MenuCompositeItem root
=
new
MenuCompositeItem(
"
root
"
,
null
);
MenuCompositeItem menu01
=
new
MenuCompositeItem(
"
menu01
"
, ResolveUrl(
"
~/Default.aspx
"
));
MenuCompositeItem menu02
=
new
MenuCompositeItem(
"
menu02
"
, ResolveUrl(
"
~/Default.aspx
"
));
MenuCompositeItem menu03
=
new
MenuCompositeItem(
"
menu03
"
, ResolveUrl(
"
~/Default.aspx
"
));
MenuCompositeItem menu04
=
new
MenuCompositeItem(
"
menu04
"
, ResolveUrl(
"
~/Page04.aspx
"
));
MenuCompositeItem menu05
=
new
MenuCompositeItem(
"
menu05
"
, ResolveUrl(
"
~/Default.aspx
"
));
MenuCompositeItem menu01_01
=
new
MenuCompositeItem(
"
menu01-01
"
, ResolveUrl(
"
~/Default.aspx
"
));
MenuCompositeItem menu01_02
=
new
MenuCompositeItem(
"
menu01-02
"
, ResolveUrl(
"
~/Page01-02.aspx
"
));
MenuCompositeItem menu01_03
=
new
MenuCompositeItem(
"
menu01-03
"
, ResolveUrl(
"
~/Default.aspx
"
));
MenuCompositeItem menu01_04
=
new
MenuCompositeItem(
"
menu01-04
"
, ResolveUrl(
"
~/Default.aspx
"
));
menu01.Children.Add(menu01_01);
menu01.Children.Add(menu01_02);
menu01.Children.Add(menu01_03);
menu01.Children.Add(menu01_04);
MenuCompositeItem menu02_01
=
new
MenuCompositeItem(
"
menu02-01
"
, ResolveUrl(
"
~/Default.aspx
"
));
MenuCompositeItem menu02_02
=
new
MenuCompositeItem(
"
menu02-02
"
, ResolveUrl(
"
~/Default.aspx
"
),
"
menu02-02
"
);
menu02.Children.Add(menu02_01);
menu02.Children.Add(menu02_02);
MenuCompositeItem menu04_01
=
new
MenuCompositeItem(
"
menu04-01
"
, ResolveUrl(
"
~/Default.aspx
"
));
MenuCompositeItem menu04_02
=
new
MenuCompositeItem(
"
menu04-02
"
, ResolveUrl(
"
~/Page04-02.aspx
"
),
"
_blank
"
);
menu04.Children.Add(menu04_01);
menu04.Children.Add(menu04_02);
root.Children.Add(menu01);
root.Children.Add(menu02);
root.Children.Add(menu03);
root.Children.Add(menu04);
root.Children.Add(menu05);
TheMenuComposite.MenuItems
=
root;
此时生成的编译运行后会生成一个没有样式Ul list ,效果如下:
因此要生成可显示和隐藏的菜单项,关键在css的设置上,开始时将二级子菜单设置为隐藏visibility: hidden;
同时定义li的hover事件,li:hover时:自菜单的 visibility要改为visible; 大致原理是这样,当然还有注意菜单项的位置
一级菜单float:left;使其能水平显示。
CSS定义如下:
.navmenu *
{
margin
:
0
;
padding
:
0
;
}
.navmenu
{
border
:
#000 1px solid
;
height
:
25px
;
}
.navmenu li
{
/*
水平菜单
*/
float
:
left
;
list-style
:
none
;
position
:
relative
;
}
.navmenu a
{
display
:
block
;
font-size
:
12px
;
height
:
24px
;
width
:
100px
;
line-height
:
24px
;
background-color
:
#CDEB8B
;
color
:
#0000ff
;
text-decoration
:
none
;
text-align
:
center
;
border-left
:
#36393D 1px inset
;
border-right
:
#36393D 1px inset
;
border-bottom
:
#36393D 1px inset
;
}
/*
单独设置一级菜单样式
*/
.navmenu > ul > li > a
{
font-size
:
11px
;
font-weight
:
bold
;
}
.navmenu a:hover
{
background
:
#369
;
color
:
#fff
;
}
/*
新增的二级菜单部分
*/
.navmenu ul ul
{
visibility
:
hidden
;
/*
开始时是隐藏的
*/
position
:
absolute
;
left
:
0px
;
top
:
24px
;
}
.navmenu ul li:hover ul, .navmenu ul a:hover ul
{
visibility
:
visible
;
}
.navmenu ul ul li
{
clear
:
both
;
/*
垂直显示
*/
text-align
:
left
;
}
/*
选中菜单项
*/
.navmenu .selected
{
padding-left
:
15px
;
background-position-x
:
0px
;
background-image
:
url(./res/selected.gif)
;
background-repeat
:
no-repeat
;
text-decoration
:
underline
;
}
定义CSS后的效果如下:
到此菜单控件已完成。已测试过可以在IE7,IE8,Chrome,Firefox中正常显示,在IE6显示可能会有问题,可以参考纯CSS多级菜单 进行修改,
本文的CSS显示部分参考了此文的介绍。
附上完整代码,如需要可自行下载修改:/Files/ruinet/WebMenu.zip