Follow @PDSAInc Use the Silverlight ListBox as an Expanding Menu - Paul Sheriff's Blog for the Real World

Paul Sheriff's Blog for the Real World

This blog is to share my tips and tricks garnered over 25+ years in the IT industry

Paul's Favorites

Use the Silverlight ListBox as an Expanding Menu

Silverlight leaves a lot of choices up to you as a developer. For example, creating a menu or navigational system for your Silverlight application is pretty much wide open. There is a template navigational application that Microsoft supplies with Visual Studio 2010 that uses HyperlinkButton controls as the menus. However, if you have more than just a few menus, you will fill up the screen pretty quickly. It would be nice if you had a way to have expanding a set of menus, so you could have your top set of menus such as “Maintenance” and “Security” that would show up to the user, and then when you click on either one of these, they would expand to reveal each menu item as shown in Figure 1.

An expanding Menu System

Figure 1: An expanding menu system.

In this article you will learn how to create an expanding menu system using the normal Silverlight ListBox control.

Create Menu User Control

The first step is to create a menu item user control that will go into each ListBoxItem control in the list box. For this you will use a Border control and a TextBlock control. Create a User Control named ucMainMenu and add the following XAML to this user control.

<Border BorderBrush="DarkGray"
        BorderThickness="1"
        Background="LightGray"
        CornerRadius="10"
        Margin="4"
        Width="80"
        Padding="4">
  <Border.Effect>
    <DropShadowEffect Color="Gray"
                      ShadowDepth="8" />
  </Border.Effect>
  <TextBlock Foreground="Black"
             HorizontalAlignment="Center"
             VerticalAlignment="Center"
             Text="{Binding Path=Text}"
             TextWrapping="Wrap" />
</Border>

Since this XAML is in a user control, you need to create a Dependency Property within this user control to bind to the TextBlock control’s Text property. Open the code behind for this user control and add the following dependency property. The easiest way to do this is to type into the editor the code snippet ‘propdp’. This will expand into a full dependency property and all you need to do is to fill out the appropriate data type and name of the property, which in this case will be ‘Text’.

public string Text
{
  get { return (string)GetValue(TextProperty); }
  set { SetValue(TextProperty, value); }
}

public static readonly DependencyProperty TextProperty =
    DependencyProperty.Register("Text", typeof(string),
    typeof(ucMainMenu), null);

Next, you need to assign the DataContext for this user control to itself in the Loaded event procedure. You need to do this so that the control will pick up any changes to the dependency property and have it rebind itself to the Text property in the TextBlock control on this user control.

private void UserControl_Loaded(object sender, RoutedEventArgs e)
{
  // Set DataContext of UserControl to itself
  // This is needed to bind 'Text' property to the
  // TextBlock Text property
  this.DataContext = this;
}

Finally, hook up the Loaded event procedure in the XAML by adding the following attribute to the UserControl definition in the XAML for the ucMainMenu user control.

Loaded="UserControl_Loaded"

Create List Box of Menu controls

Now that you have your Main Menu user control created, you will need to use this user control in each ListBoxItem of your list box. The first thing you will do on the MainPage.xaml is import the namespace for your Silverlight project. In my case I named my Silverlight project “SLListBoxExpandingMenu”.

xmlns:src="clr-namespace:SLListBoxExpandingMenu"

After you have added this XML Namespace, you can now create each ListBoxItem within a ListBox as shown below.

<ListBox Style="{StaticResource Menu.ListBox}">
  <ListBoxItem>
    <src:ucMainMenu Text="Maintenance" />
  </ListBoxItem>
  <ListBoxItem>
    <src:ucMainMenu Text="Menus" />
  </ListBoxItem>
  <ListBoxItem>
    <src:ucMainMenu Text="Messages" />
  </ListBoxItem>
  <ListBoxItem>
    <src:ucMainMenu Text="Security" />
  </ListBoxItem>

  ...
  ...

</ListBox>

To make this ListBox control look like Figure 2 you need to style the list box using the Style shown in the Resources below.

<UserControl.Resources>
  <Style TargetType="ListBox"
          x:Key="Menu.ListBox">
    <Setter Property="MinHeight"
            Value="80" />
    <Setter Property="VerticalAlignment"
            Value="Top" />
    <Setter Property="ItemsPanel">
      <Setter.Value>
        <ItemsPanelTemplate>
          <StackPanel Orientation="Horizontal" />
        </ItemsPanelTemplate>
      </Setter.Value>
    </Setter>
  </Style>
</UserControl.Resources>

After styling the ListBox you should end up with a menu system that looks like Figure 2.

Each ListBoxItem of the ListBox is a user control made of a Border and TextBlock control

Figure 2: Each ListBoxItem of the ListBox is a user control made of a Border and TextBlock control.

Make a 2nd Level ListBox

Now it is time to take the 2 menu items after the Maintenance menu and make them invisible until you click on the Maintenance menu item. To accomplish this, you will put another list box inside of a ListBoxItem control. This new list box will hold the set of 2nd level menus that will be expanded. You will need to hide this ListBoxItem control until the user clicks on the Maintenance list box item. To do this you will use a little data binding and a Boolean to visibility value converter.

The way this works is to give a Name to the Maintenance ListBoxItem control. Then the next ListBoxItem control you set the Visibility property to a data binding back to the Maintenance list box item. You will need the converter class to convert from True/False to a Visibility enumeration. You will bind this new ListBoxItem control’s Visibility property to the IsSelected property of the previous ListBoxItem control.

<ListBoxItem Name="lbMaint">
  <src:ucMainMenu Text="Maintenance >>" />
</ListBoxItem>
<ListBoxItem Visibility="{Binding ElementName=lbMaint,
                   Path=IsSelected,
                   Converter={StaticResource boolVisibility}}">
  <ListBox>
   ...
  </ListBox>
</ListBoxItem>

The BooleanToVisibility Converter Class

A value converter class is a very simple class that just has two methods; Convert and ConvertBack. The Convert method is the only one you need to implement. Below is the code that checks the ‘value’ parameter to determine whether or not to return a Visible or Collapsed value.

public class BooleanToVisibilityConverter : IValueConverter
{
  public object Convert(object value, Type targetType,
                        object parameter, CultureInfo culture)
  {
    if ((bool)value)
      return Visibility.Visible;
    else
      return Visibility.Collapsed;
  }

  public object ConvertBack(object value, Type targetType,
                            object parameter, CultureInfo culture)
  {
    throw new NotImplementedException("BooleanToVisibility
             ConvertBack Method Not Implemented");
  }
}

Next you add a reference to this converter in the UserControl.Resources section of your MainPage.xaml page.

<src:BooleanToVisibilityConverter x:Key="boolVisibility" />

You can now move the two ListBoxItem controls after the Maintenance menu into the new list box you created in the data bound ListBoxItem control.

<ListBox Style="{StaticResource Menu.ListBox}">
  <ListBoxItem Name="lbMaint">
    <src:ucMainMenu Text="Maintenance >>" />
  </ListBoxItem>
  <ListBoxItem Visibility="{Binding ElementName=lbMaint,
                   Path=IsSelected,
                   Converter={StaticResource boolVisibility}}">
    <ListBox Style="{StaticResource Menu.ListBox.2ndLevel}">
      <ListBoxItem>
        <src:ucMainMenu Text="Menus" />
      </ListBoxItem>
      <ListBoxItem>
        <src:ucMainMenu Text="Messages" />
      </ListBoxItem>
    </ListBox>
  </ListBoxItem>

...
...

You now just repeat this process for any other “sub-menus” that you wish to create. Give a name to each one so you can data bind on the IsSelected property.

Summary

Creating an expanding menu system is very simple to do with just one little value converter class. Other than that you can do everything in XAML. The only thing you need to do is add code to respond to the SelectionChanged event procedure and call the appropriate method to load your user controls. An idea here would be to add a Tag property to your ListBoxItem controls that has the name of the control to load. You could then use reflection to load the user control instead of having to have a switch or Select statement.

NOTE: You can download the complete sample code at my website. http://www.pdsa.com/downloads. Choose Tips & Tricks, then “Use the Silverlight ListBox as an Expanding Menu" from the drop-down.

Good Luck with your Coding,
Paul Sheriff

** SPECIAL OFFER FOR MY BLOG READERS **
We frequently offer a FREE gift for readers of my blog. Visit http://www.pdsa.com/Event/Blog for your FREE gift!

Comments

CJ said:

Have you done this in SL4 where the Menu User Control is already created for you? I'm fairly new to SL and I'm having a hard time trying to implement this in a SL4 Business Application where there's hyperlink buttons.

# July 21, 2011 12:57 PM

Brendan said:

thanks for sharing the whole coellction tht you did during last six months. keep it up kunal. your articles are very useful for me to understand silverlight. in each article, i am learning new new things about silverlight.i started working on silverlight recently and want to continue with it. though i am working in silverlight 3, but in my past time i am exploring silverlight 4 by reading various articles & tutorials. your tutorials are one of them.again thanks for contributing your knowledge. want to read more from you.

# October 29, 2012 2:49 PM