Click here to Skip to main content
6,629,885 members and growing! (22,291 online)
Email Password   helpLost your password?
Web Development » Silverlight » Controls     Intermediate License: The Code Project Open License (CPOL)

Reusable Silverlight 2 Popup Menu

By Philip Kin

A popup menu implementation with submenus.
C#, .NET, XAML, Silverlight, Dev
Version:4 (See All)
Posted:15 Jan 2009
Views:12,452
Bookmarked:23 times
Announcements
Loading...
 
Search    
Advanced Search
Add to IE Search
printPrint   add Share
      Discuss Discuss   Broken Article?Report  
6 votes for this article.
Popularity: 3.50 Rating: 4.50 out of 5

1

2

3
3 votes, 50.0%
4
3 votes, 50.0%
5

Menu in action

Introduction

While Silverlight has a lot of useful controls, it seems to be lacking support for some of the things we've all become accustomed to. Recently, I had the "pleasure" of putting together a dropdown menu with submenus built from our database. This was tricky for multiple reasons. The code presented here is a reusable menu driven by a list of items with sub menu support.

Using the Code

To embed the menu in a page, simply add the PopupMenuExample namespace to the XAML as usual.

xmlns:pop="clr-namespace:PopupMenuExample"

And then, add it in to the XAML layout (preferably in a vertical StackPanel with the item that will trigger it).

<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>

Some code has to be added to add the menu items and link the menu to the popup trigger. This could possibly be done in the XAML at some point, though I don't have the skills to do that just yet. Here's the code from the sample project that initializes the menu:

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;

Now, that isn't terribly useful, as most times, it will be data driven (or at least, it will be for me). Here's an example of setting the menu items using a LINQ query:

PopupMenu1.SetMenuItems(
from item in db.MainMenu 
select new PopupMenuItem()
{ 
    Heading = item.Heading, 
    Tag=item.Uri, 
    Id=item.Id, 
    ParentId=item.ParentId
});

To capture the item clicks, you simply handle the ItemClick event.

PopupMenu1.ItemClick += new PopupMenuItemClickHandler(PopupMenu1_ItemClick);

    ...

void PopupMenu1_ItemClick(object sender, PopupMenuItem item)
{
    txtClicked.Text = "You last clicked on: " + (string)item.Tag;
}

Points of Interest

In order to catch when the mouse comes out of the menu (and all child menus or the trigger object), a timer is used to give the mouse some time to enter the new object (or the UI to catch up and send the MouseEnter event).

/// <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);
}

History

  • 01/16/2009: Fixed source download link.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

About the Author

Philip Kin


Member

Occupation: Software Developer (Senior)
Company: Lifeguard America, Inc.
Location: United States United States

Other popular Silverlight articles:

Article Top
You must Sign In to use this message board.
FAQ FAQ 
 
Noise Tolerance  Layout  Per page   
 Msgs 1 to 5 of 5 (Total in Forum: 5) (Refresh)FirstPrevNext
GeneralKeyboard navigaton and hotkey support PinmemberAndrusM10:15 19 Jan '09  
GeneralRe: Keyboard navigaton and hotkey support PinmemberPhilip Kin9:41 20 Jan '09  
GeneralRe: Keyboard navigaton and hotkey support PinmemberAndrusM10:09 20 Jan '09  
GeneralThe source file can't download !!!! Pinmemberfirehang_16619:48 15 Jan '09  
GeneralFixed PinmemberPhilip Kin5:06 16 Jan '09  

General General    News News    Question Question    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

PermaLink | Privacy | Terms of Use
Last Updated: 15 Jan 2009
Editor: Smitha Vijayan
Copyright 2009 by Philip Kin
Everything else Copyright © CodeProject, 1999-2009
Web20 | Advertise on the Code Project