可重用的 Silverlight 2 弹出菜单






4.53/5 (7投票s)
一个带有子菜单的弹出菜单实现。
引言
虽然 Silverlight 拥有许多有用的控件,但似乎缺乏对我们都已习惯的一些功能的的支持。最近,我“荣幸”地构建了一个从数据库构建的带有子菜单的下拉菜单。这很棘手,原因有很多。这里提供的代码是一个由项目列表驱动,并支持子菜单的可重用菜单。
Using the Code
要在页面中嵌入菜单,只需像往常一样将 PopupMenuExample
命名空间添加到 XAML 中即可。
xmlns:pop="clr-namespace:PopupMenuExample"
然后,将其添加到 XAML 布局中(最好是在一个垂直的 StackPanel
中,与将触发它的项目一起)。
<StackPanel HorizontalAlignment="Left" VerticalAlignment="Top">
<Border x:Name="PopupBorder" HorizontalAlignment="Left"
Height="30" Width="100" BorderBrush="Beige"
BorderThickness="1" Background="LightGray">
<TextBlock HorizontalAlignment="Center"
VerticalAlignment="Center">Menu Root</TextBlock>
</Border>
<pop:PopupMenu x:Name="PopupMenu1" />
<TextBlock HorizontalAlignment="Left" x:Name="txtClicked"
Margin="0 100 0 0">You last clicked on: Nothing</TextBlock>
</StackPanel>
需要添加一些代码来添加菜单项并将菜单链接到弹出触发器。这可能在某个时候在 XAML 中完成,尽管我还没有掌握这项技能。这是示例项目初始化菜单的代码
PopupMenu1.SetMenuItems(new List&;lt;popupmenuitem>()
{
new PopupMenuItem(){ Heading = "Item with no submenu. (Tag: Bacon)",
Tag="Bacon", Id=0, ParentId=null},
new PopupMenuItem(){ Heading = "Item with submenu. (Tag: Eggs)",
Tag="Eggs", Id=1, ParentId=null},
new PopupMenuItem(){ Heading = "Submenu Item. {Tag: Easter}",
Tag="Easter", Id=2, ParentId=1},
new PopupMenuItem(){ Heading = "Submenu Item with submenu. (Tag: Foo)",
Tag="Foo", Id=3, ParentId=1},
new PopupMenuItem(){ Heading = "Sub-Submenu Item. (Tag: Bar}",
Tag="Bar", Id=4, ParentId=3}
});
PopupMenu1.PopupFrom = PopupBorder;
现在,这并不是特别有用,因为大多数情况下,它将是数据驱动的(或者至少对我来说是这样)。这是一个使用 LINQ 查询设置菜单项的示例
PopupMenu1.SetMenuItems(
from item in db.MainMenu
select new PopupMenuItem()
{
Heading = item.Heading,
Tag=item.Uri,
Id=item.Id,
ParentId=item.ParentId
});
要捕获项目点击,只需处理 ItemClick
事件即可。
PopupMenu1.ItemClick += new PopupMenuItemClickHandler(PopupMenu1_ItemClick);
...
void PopupMenu1_ItemClick(object sender, PopupMenuItem item)
{
txtClicked.Text = "You last clicked on: " + (string)item.Tag;
}
关注点
为了捕获鼠标离开菜单(以及所有子菜单或触发对象)的时间,使用定时器给鼠标一些时间进入新对象(或者 UI 赶上并发送 MouseEnter
事件)。
/// <summary>
/// Catches the mouse leaving this menu (or a child menu).
/// </summary>
void Menu_MouseLeave(object sender, MouseEventArgs e)
{
//set the timer to see if the user is out of the menu.
_popTimer.Change(100, System.Threading.Timeout.Infinite);
//Bubble up an event for parents to see.
if (_childMouseLeave != null)
{
_childMouseLeave(sender, e);
}
}
/// <summary>
/// Catches the mouse entring this menu (or a child menu).
/// </summary>
void Menu_MouseEnter(object sender, MouseEventArgs e)
{
//make sure we are still open.
popMenu.IsOpen = true;
//stop the timer if its running.
_popTimer.Change(System.Threading.Timeout.Infinite,
System.Threading.Timeout.Infinite);
//Bubble up an event for parents to see.
if (_childMouseEnter != null)
{
_childMouseEnter(sender, e);
}
}
/// <summary>
/// When the timer elapses, the menu is closed.
/// </summary>
void PopupTimer_Elapsed(object state)
{
popMenu.Dispatcher.BeginInvoke(() => popMenu.IsOpen = false);
}
/// <summary>
/// Catches the mouse leaving this menu's popup trigger.
/// </summary>
void _popupFrom_MouseLeave(object sender, MouseEventArgs e)
{
_popTimer.Change(100, System.Threading.Timeout.Infinite);
}
/// <summary>
/// Catches the mouse entering this menu's popup trigger.
/// </summary>
void _popupFrom_MouseEnter(object sender, MouseEventArgs e)
{
popMenu.IsOpen = true;
_popTimer.Change(System.Threading.Timeout.Infinite,
System.Threading.Timeout.Infinite);
}
历史
- 2009/01/16:修复了源代码下载链接。