We continue our serie of animated menus, this time : the sliding menu.
Project / source code
As usual, our sliding menu is declared in a XML file,
Menu.xml, inserted as a resource :
<?xml version="1.0" encoding="utf-8" ?>
<Menu>
<Item Text="Italy" >
<Item Miniature="MiniVenice.jpg" Id="11" Text="Venice, Grand Canal"/>
.....
<Item Miniature="MiniVatican.jpg" Id="15" Text="Vatican, St. Peter's Square" />
</Item>
<Item Text="USA" >
<Item Miniature="MiniYosemite.jpg" Id="21" Text="Yosemite National park" />
.....
<Item Miniature="MiniGrand Canyon.jpg" Id="23" Text="Grand Canyon National Park"/>
</Item>
.....
</Menu>
The user has just one constraint : reserve space for the menu on top of anything else in the window (this explains the
Canvas.ZIndex) . Miniatures must be included as resources (they are displayed in sub-menus). The user can then handle the
Click event :
<Grid x:Name="LayoutRoot" Background="White" >
<Grid x:Name="menuGrid" Canvas.ZIndex="99" Height="40" VerticalAlignment="Top" >
<gl:Menu Click="menuGrid_Click" />
</Grid>
<Grid x:Name="mainGrid" >
.....
</Grid>
</Grid>
As we did for other menu, we build a Silverlight user control named
Menu.xaml in the
glMenu namespace. Our menu as a Grid containing a Canvas for the sub-menus and an horizontal StackPanel for the main menu items. Why a Canvas for the sub-menus ? They are animated (down animation for opening and up animation for closing) and it is not (unfortunately) possible to animate the
Margin property :
<Grid x:Name="MenuRoot" >
.....
<Canvas x:Name="canSubMenus" />
<StackPanel x:Name="spMainMenu" Orientation="Horizontal" Loaded="spMainMenu_Loaded" >
....
</StackPanel>
</Grid>
Since main menu items and sub-menu items are quite different, we create two classes :
MainMenuItem and
SubMenuItem. In memory, we also keep a list of main menu items and a table for sub-menu items (the number of entries in this table depends on the number of main menu items) :
List<MainMenuItem> lstMainMenuItems;
List<SubMenuItem>[] tabSubMenuItems;
The main menu is first build in the
spMainMenu_Loaded function. Thanks to Linq for Xml, we analyze the XML file to find the main menu items :
lstMainMenuItems = new List<MainMenuItem>();
XElement xmlRoot = XElement.Load("Menu.xml");
getMainMenuItems(xmlRoot);
.....
void getMainMenuItems(XElement xml)
{
var lstItems = from p in xml.Elements("Item") select p;
foreach (var el in lstItems)
lstMainMenuItems.Add(new MainMenuItem {Text=el.Attribute("Text").Value, xElem=el});
}
The main menu is then build using Silverlight UI elements : a
Grid including a
TextBlock (indeed two
TextBlock to give a 3D effect to the display). For each main menu item, we handle the
MouseEnter event (to make visible the corresponding sub-menu), the
MouseLeave (to hide it) but also the
MouseMove (leaving the main menu item thru the bottom side must leave the sub-menu as it is).
The sub-menus are then build (at this time, we know the number of sub-menu items). All the sub-menus are placed in a Canvas (
canSubMenus). Each sub-menus (three here) are build on a canvas. Each sub-menu item (we have 5 for Italy and 3 for USA) are also based on a canvas containing an image (the miniature). For each of these canvas, we handle the
MouseEnter,
MouseLeave and
MouseLeftButtonDown events.
Source code is included, as usual.