Menus, part IV : collapsible menu

by gleblanc 10. November 2008 17:23

In this post, we will implement a collapsible menu, animated of course. It's amazing to see how easily any .NET educated programmer (even WinForms only) can add functionnalities to Silverlight applications.


Project / source code

Our collapsible menu is declared in a XML file (Menu.xml, inserted as a resource) :

 <?xml version="1.0" encoding="utf-8" ?>
 <Items>
  <Item Text="China" Id="10" />
  <Item Text="USA" Id="30" >
   <Item Text="Grand Canyon" Id="31" />
   <Item Text="Yosemite"     Id="32" />
   .....
  </Item>
  <Item Text="Egypt" Id="40" />
  .....
 </Items>

To build the collapsible menu in our Silverlight application, we first add a Silverlight user control, named CollapsibleMenu (the CollapsibleMenu.xaml and CollapsibleMenu.xaml.cs files are then created by Visual Studio). We force the namespace named glMenu (gl for our own initials). In the CollapsibleMenu.xaml file, we suppress Width and Height properties. Business as usual for a user control.

Our collapsible menu is implemented as an horizontal StackPanel, with two elements : one (a vertical StackPanel with menu items) for the menu itself (horizontally collapsible) and a bordered TextBlock (22 pixels wide) for the tab (always visible, with "Menu" written vertically).

 <StackPanel Orientation="Horizontal" >
  <StackPanel x:Name="spMenu" Orientation="Vertical" ..... >
   .....
  </StackPanel>
  <Border CornerRadius="0,15,15,0" Width="22" VerticalAlignment="Top" ..... >
   <TextBlock x:Name="tab" Text="Menu" TextWrapping="Wrap" ...... />
  </Border>
 </StackPanel>

For the TextBlock (named tab), we also specify some font properties (FontFamily, FontSize, etc.) and handle three events : MouseEnter and MouseLeave but also MouseMove (leaving the tab thru the left or right sides must have a different effect : keeping the menu as it is or collapsing it).

The menu itself is a vertical StackPanel (with an initial width of 0 pixel) that will be populated by program in the function that handles the Loaded event :

 <StackPanel x:Name="spMenu" Orientation="Vertical" Width="0" Loaded="spMenu_Loaded"
             MouseLeave="spMenu_MouseLeave" >
   .....
 </StackPanel>

We handle the Loaded event (to initialize the menu from the XML file) and the MouseLeave event (to progressively reduce its width to 0). Inside this StackPanel, we define an animation (to horizontally and progressively expand or collapse the menu in one second) :

 <StackPanel x:Name="spMenu" ..... >
  <StackPanel.Resources>
   <Storyboard x:Name="stb" >
    <DoubleAnimation x:Name="da" Storyboard.TargetName="spMenu"
                     Storyboard.TargetProperty="Width" Duration="0:0:1" />
   </Storyboard>
  </StackPanel.Resources>
 </StackPanel>
Q

In the Loaded function, we read the XML file and prepare the menu (first as a list of MenuItem objects) and then (in the PrepareMenu function) as a set of XAML tags :

 List<MenuItem> lstMenuItems;
 private void spMenu_Loaded(object sender, RoutedEventArgs e)
 {
  lstMenuItems = new List<MenuItem>();
  XElement xmlRoot = XElement.Load("Menu.xml");
  getMenuItems(xmlRoot);
  PrepareMenu();
 }

The MenuItem class (also created in the glMenu namespace) is

 public class MenuItem
 {
  public MenuItem(string aText, int aId, int aLevel, int acountSubItems)
  {
   Text = aText; Id = aId; Level = aLevel; countSubItems = acountSubItems;
  }
  public string Text {get; set;}
  public int Id {get; set;}
  public int Level { get; set; }
  public int countSubItems {get; set;}
 }

Level is 0 for a main menu item (for instance USA) and 1 for a submenu item (for instance Yosemite). The field countSubItems contains the number of sub-items for a main menu item (5 for Italy).

Linq provides an incomparable help in the task of analyzing the XML file (do not forget to add a reference to System.Xml.Linq) :

 void getMenuItems(XElement xml)
 {
  var lstItems = from p in xml.Elements("Item") select p;
  foreach (var el in lstItems)
  {
   string Text = el.Attribute("Text").Value;
   int Id; Int32.TryParse(el.Attribute("Id").Value, out Id);
   if (el.HasElements == false)
    lstMenuItems.Add(new MenuItem(Text, Id, 0, 0));
   else
   {
    // this main menu item has one or several sub-menu items
    lstMenuItems.Add(new MenuItem(Text, Id, 0, el.Elements("Item").Count()));
    var subItems = from pSub in el.Elements("Item") select pSub;
    foreach (var sub in subItems)
    {
     Text = sub.Attribute("Text").Value;
     Int32.TryParse(sub.Attribute("Id").Value, out Id);
     lstMenuItems.Add(new MenuItem(Text, Id, 1, 0));
    }
   }
  }
 }

The menu is a vertical StackPanel. Each main menu item is a Grid. Each sub-menu item is also a Grid but included in a vertical StackPanel containing all sub-menu items :

 void PrepareMenu()
 {
  int N = lstMenuItems.Count;
  for (int n=0; n<N; n++)
  {
   MenuItem mi = lstMenuItems[n];
   PrepareMainMenuItem(mi);
   if (mi.countSubItems > 0)
   {
    PrepareSubMenuItems(mi);
    n += mi.countSubItems;
   }
  }
  spMenu.Width = 0;  // menu initially fully collapsed
  ..... // add storyboard to main items with submenu
 }

At the end of the PrepareMenu function, we also need to add a Storyboard (to vertically and progressively expand or callapse a sub-menu). This is only necessary for main menu items that have sub-menu items.

In the PrepareMainMenuItem function, we prepare the XAML for a specific main menu item : a Grid (with a linear gradient brush for Background) plus a TextBlock for the text. We handle the MouseLeftButtonDown (to open the associated sub-menu but it could be to activate a main menu item without sub-menu).

In the PrepareSubMenuItems function, we prepare the XAML for the sub-menu of a specific main menu item : a vertical StackPanel containing as many Grid as they are sub-menu items in this main menu item). This Grid is made of a Rectangle (for Background and Stroke) and a TextBlock.

As we did in previous posts, our collapsible menu is able to generate the Click event (the MenuEventArgs is just a class derived from EventArgs, plus the Id field as complementary information) :

 public delegate void MenuEventHandler(object sender, MenuEventArgs e);
 public event MenuEventHandler Click;
 ....
 MenuEventArgs args = new MenuEventArgs(); args.itemId = Id;
 if (Click != null)     // if Click event handled by the user
    Click(this, args);

In Page.xaml, the user specifies the collapsible menu with (do not forget to put it on top) :

<UserControl .....
    xmlns:gl="clr-namespace:glMenu"
    ..... >
    <Grid x:Name="LayoutRoot" Background="White">
      <Grid x:Name="menuGrid" Canvas.ZIndex="99"  >
       <gl:CollapsibleMenu x:Name="menu" VerticalAlignment="Top" Margin="0, 20, 0, 0"
                           Click="myMenu_Click" />
      </Grid>
      <Grid ..... >        here the main grid for the Silverlight application
       .....
      </Grid>
    </Grid>

That's all, folks !

Tags:

Comments

11/11/2008 6:41:02 PM #

Pingback from mgalinks.wordpress.com

2008 November 11 - Links for today « My (almost) Daily Links

mgalinks.wordpress.com

11/12/2008 1:54:08 PM #

Trackback from Community Blogs

Silverlight Cream for November 11, 2008 - 2 -- #425

Community Blogs

11/12/2008 4:50:43 PM #

Pingback from ebnerj.at

Menüs in Silverlight

ebnerj.at

11/17/2008 8:26:29 AM #

Trackback from #.think.in

#.think.in infoDose #7 (10th Nov - 15th Nov)

#.think.in

3/6/2009 8:57:40 AM #

Thank You ! I was just looking for this.

nikhil760 India

5/24/2009 12:01:55 AM #

Bon jour M. Leblanc
cette piece pour silverlight est tres elegant et belle.....

varun India

6/28/2009 8:11:55 AM #

Exactly what i was looking for

Wohlfarth Real Estate

7/14/2009 3:04:35 PM #

I like your blog curently we are looking for a part time article writer would you be interested?

Philip Stein United States

8/5/2009 6:45:14 AM #

Nice post! GA is also my biggest earning. However, it�s not a much.

payday loans United States

8/5/2009 6:45:17 AM #

I don�t usually reply to posts but I will in this case. WoW Smile

payday loans United States

8/11/2009 3:40:31 AM #

I keep listening to the news speak about getting free online grant applications so I have been looking around for the best site to get one.Smile

cash loans United States

8/11/2009 3:40:34 AM #

Hello. Great job. I did not expect this on a Wednesday. This is a great story. Thanks!

cash loans United States

8/19/2009 8:47:03 PM #

There is obviously a lot to know about this.  I think you made some good points in Features also.

Thomas United States

8/19/2009 8:47:07 PM #

Excellent blog with lots of useful information. Are there any forums that you recommend I join?

Sue United States

8/21/2009 3:41:17 PM #

Thanks for sharing your views on the topic. It makes one think and look the other side of the story.

Cheque United Kingdom

9/14/2009 7:53:30 PM #

I havent any word to appreciate this post.....Really i am impressed from this post....the person who create this post it was a great human..thanks for shared this with us.

payday online United States

9/14/2009 8:26:14 PM #

I havent any word to appreciate this post.....Really i am impressed from this post....the person who create this post it was a great human..thanks for shared this with us.

payday online United States

9/16/2009 7:55:09 PM #

I havent any word to appreciate this post

Livescores United States

9/16/2009 7:56:14 PM #

Excellent blog with lots of useful information.

live football results United States

9/16/2009 7:57:19 PM #

Thanks for sharing

live scores basketball United States

9/16/2009 7:58:17 PM #

There is obviously a lot to know about this.

cricket live scores United States

9/16/2009 7:59:32 PM #

Thank You ! I was just looking for this.

Sports scores United States

9/16/2009 8:00:39 PM #

Hello. Great job.

cheapest kamagra United States

9/16/2009 8:01:33 PM #

I think you made some good points in Features also.

online kamagra United States

9/16/2009 8:02:13 PM #

great website

kamagra uk United States

9/16/2009 8:03:24 PM #

This is a great story. Thanks!

buy kamagra online United States

9/16/2009 8:04:03 PM #

Nice post

kamagra pills United States

9/21/2009 10:57:44 AM #

We are a group of volunteers and starting a new initiative in a community. Your blog provided us valuable information to work on.You have done a marvellous job!

payday loans United States

9/21/2009 11:24:14 AM #

We are a group of volunteers and starting a new initiative in a community. Your blog provided us valuable information to work on.You have done a marvellous job!

payday loans United States

9/23/2009 7:31:31 AM #

This menu tutorial is fantastic. I'm using them on all my sites.

cd rates United States

9/30/2009 11:33:27 AM #

Pingback from ebnerj.at

Menüs in Silverlight

Tiffany Rings People's Republic of China

10/5/2009 8:40:06 PM #

You got a really useful blog I have been here reading for about an hour. I am a newbee and your success is very much an inspiration for me. The first page doesn?t need to be just a dream anymore...

Florida defense attorneys United States

10/8/2009 6:57:07 PM #

I completely agree with the above comment, the internet is with a doubt growing into the most important medium of communication across the globe and its due to sites like this that ideas are spreading so quickly.

Pinball games United States

10/9/2009 7:05:35 PM #

I have never been interested in post on the web but the post has changed my mind.  

web design United Kingdom

10/10/2009 4:20:38 PM #

Admiring the time and effort you put into your blog and detailed information you offer!

Web design United Kingdom

Powered by BlogEngine.NET 1.5.0.7
Theme by Mads Kristensen

About the author

Gerard Leblanc is the author of several books (in french) on C++, C#, .NET and Silverlight (Eyrolles, Paris as publisher). See www.gleblanc.eu as the companion web site for these books (included sample programs).
He is Microsoft MVP for Silverlight.

MVP logo