Follow @PDSAInc April 2011 - Posts - 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

April 2011 - Posts

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!

Add Gradient Background to Mirror Image

In my last blog post I showed you how to create a mirror image as shown in Figure 1. This simple image with a reflection is a nice effect, but it does look a little flat and not very interesting just sitting directly on the user control. In this blog post you will learn how to add a background using a border, a linear gradient and a drop shadow to give this reflection a little more depth and interest to the user’s eye as shown in Figure 3.

A mirror image in Silverlight 

Figure 1: A mirror image in Silverlight

Creating Gradients in Visual Studio

Gradients are pretty easy to add in Visual Studio. There is no need to go into Expression Blend. Simply click on a Grid or Border control, then go to the Properties Window and drop down the arrow next to the Background property as shown by callout #1 in Figure 2. You can then select the 3rd icon from the left just above color palette (callout #2). That is the Linear Gradient brush. Then down below the color palette (callout #3) you can select whether you want a horizontal, vertical or radial type of gradient.

After that it is just a matter of setting colors for 2 or more stops of the gradient. When using colors for a gradient make sure you keep the colors very similar for each stop. Just vary by the lightness or darkness of the same color. For example having a gradient go from DarkGray to LightGray looks very good. However, going from a DarkBlue to a Yellow would not look very good.

You can add Linear Gradients right in Visual Studio 

Figure 2: You can add Linear Gradients right in Visual Studio

You should try creating some linear and radial gradients on the Grid of a Silverlight User Control to get a feel for how to build these visual elements. As I mentioned, keep the colors close together. The key to a good looking interface is subtlety.

Create Border around Mirror Reflection Images

The easiest method to get your mirror reflection image on a background as shown in Figure 3 is to wrap a Border control around the StackPanel. On the Border you will need to put a LinearGradientBrush on the Background and use a DropShadowEffect on the Effect property. Let’s take a look at how to build these.

 Adding a Border, Gradient Background and Drop Shadow around your reflection will add more visual appeal

Figure 3: Adding a Border, Gradient Background and Drop Shadow around your reflection will add more visual appeal

Build a DropShadowEffect

A Border control (and other controls) have an Effect property where you can add a drop shadow. I like to make a DropShadowEffect resource so I can reuse that effect in many places. Place the following XAML in your App.xaml file or resource dictionary.

<DropShadowEffect x:Key="Border.Shadow"
                  Color="Gray"
                  ShadowDepth="10"
                  BlurRadius="2" />

Build a LinearGradientBrush

Now it is time to add the Linear Gradient Brush that will be the background of our Border control. The particular gradient brush used in this sample has 5 stops in it. All are various shades of gray as shown in the XAML below.

<LinearGradientBrush StartPoint="0.5,0.0"
                      EndPoint="0.5,0.5"
                      x:Key="Border.Brush">
  <GradientStop Color="Gray"
                Offset="0" />
  <GradientStop Color="#FFA4A4A4"
                Offset="0.6" />
  <GradientStop Color="#FF969393"
                Offset="0.85" />
  <GradientStop Color="#FFC4C4C4"
                Offset="0.75" />
  <GradientStop Color="Silver"
                Offset="1" />
</LinearGradientBrush>

You will notice that the 4th stop has an offset that is less than the 3rd stop. This is what gives the whiter shade of gray that is in between the two darker grays in the background. Using this technique gives your background a depth like there is a corner in that location.

Build Style for Border

Now that you have these two resources (the gradient brush and the drop shadow) you will now build a <Style> for the Border control that we will put around the StackPanel that contains the mirror images. Here is the style I used for this sample, but feel free to modify this to suit your needs.

<Style TargetType="Border"
       x:Key="Border.Style">
  <Setter Property="Background"
          Value="{StaticResource Border.Brush}" />
  <Setter Property="Effect"
          Value="{StaticResource Border.Shadow}" />
  <Setter Property="CornerRadius"
          Value="20" />
  <Setter Property="Margin"
          Value="8,8,16,8" />
  <Setter Property="VerticalAlignment"
          Value="Top" />
</Style>

This style is created along with your other resources and then is applied to your Border control.

<Border Style="{StaticResource Border.Style}">
  ... <StackPanel> here
</Border>

Summary

Having a couple of good looking gradients in your toolbox and adding drop shadow effects to your user controls can add a lot of character to your application. Experiment with creating your own styles within Visual Studio. Yes, Expression Blend can be helpful for certain things in XAML, but Visual Studio can be used for everything done in this blog post.

NOTE: You can download the complete sample code at my website. http://www.pdsa.com/downloads. Choose Tips & Tricks, then “Add Gradient Background to Mirror Image" 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!

More Posts