Wahlin on .NET

Creating a Flyout StackPanel Using Silverlight Animations

A header menu that expands and contracts as users mouse over it can be easy to create. Dan shows you how.

Silverlight's StackPanel control provides a flexible way for arranging child controls horizontally or vertically in a user interface. By using it, you can create dynamic interfaces that can adapt to different screen sizes. If you're new to the StackPanel control you can read my previous column to learn more about it.

In this article, I'm going to take a break from discussing layout controls and showing how a StackPanel control can be animated using Storyboard objects. I'll demonstrate how to create a simple header menu that expands when a user mouses over it and contracts as they mouse out of it. There are several different ways to achieve this effect, but I'll focus on a very simple technique you can use.

To create a fly out header, you'll first need to place the header controls or links in a StackPanel control as shown below. Keep in mind that Silverlight provides other layout controls such as Grid and Canvas that can also be used:

 <StackPanel Orientation="Vertical" 
  HorizontalAlignment="Left">
   <StackPanel x:Name="spButtons" Orientation="Horizontal"  
    Background="Black" Height="40" Width="500">
      <HyperlinkButton x:Name="btn1" Content="Home"        
       Style="{StaticResource hlStyle}"/>
      <HyperlinkButton x:Name="btn2" Content="Products" 
       Style="{StaticResource hlStyle}"/>
      <HyperlinkButton x:Name="btn3" Content="Support" 
       Style="{StaticResource hlStyle}" />
      <HyperlinkButton x:Name="btn4" Content="Download" 
       Style="{StaticResource hlStyle}" />
      <HyperlinkButton x:Name="btn5" Content="Contact Us" 
       Style="{StaticResource hlStyle}" />
   </StackPanel>
   <StackPanel x:Name="spContent" Height="400">
      <TextBlock Text="Content Goes Here" Margin="20" />
   </StackPanel>
</StackPanel>

This example uses a parent StackPanel control to arrange two child StackPanel controls vertically. The header menu is created using a child StackPanel with a name of spButtons. Figure 1 shows what the simple user interface looks like at runtime.

You can add a "flyout" effect to the header menu quite easily by using Storyboard objects. If you're new to Storyboards, check out some of my previous articles on Silverlight animation concepts. An example of defining a Storyboard in XAML to collapse a menu is shown here:

<Storyboard x:Name="Shrink">
   <DoubleAnimation Storyboard.TargetName="spButtons" 
     Storyboard.TargetProperty="Height"
     From="40" To="14" Duration="00:00:00.5" />
</Storyboard>

This XAML code defines a Storyboard named Shrink that contains a DoubleAnimation. The DoubleAnimation is responsible for changing the Height property of the StackPanel named spButton from 40 to 14 over a period of a half-second.

Another Storyboard can be created to expand or "flyout" the menu using a similar animation. The following shows a Storyboard named Grow that changes the Height back to a value of 40 over a half-second:

<Storyboard x:Name="Grow">
   <DoubleAnimation Storyboard.TargetName="spButtons" 
     Storyboard.TargetProperty="Height"
     From="14" To="40" Duration="00:00:00.5" />
</Storyboard>

It's important to note that Storyboard objects can also be reversed, which could work in this situation because one Storyboard could be used to expand and collapse the menu. However, for this particular example I decided to use two separate Storyboard objects to keep the concepts basic.

Once the Storyboard objects are defined, you'll need a way to start them so that the associated animations play and the header menu expands and collapses. This can be accomplished by handling the StackPanel's MouseEnter and MouseLeave events. To do this, add the appropriate attributes to the StackPanel in the XAML, as shown next:

<StackPanel x:Name="spButtons" Orientation="Horizontal"  
  Background="Black" Height="40" Width="500" 
  MouseEnter="spButtons_MouseEnter" 
  MouseLeave="spButtons_MouseLeave">

...

</StackPanel>

When you add these attributes into the XAML, you'll be prompted by Visual Studio 2008 to create an event handler in the code-behind file. Examples of event handlers are shown below:

private void spButtons_
  MouseEnter(object sender, MouseEventArgs e)
{
   //Only maximize stack panel if it's currently minimized
   if (_State != State.Minimized) return;
   Grow.Begin();
   _State = State.Maximized;
}

private void spButtons_
  MouseLeave(object sender, MouseEventArgs e)
{
   //Only minimize stack panel if it's currently maximized
   if (_State != State.Maximized) return;
   Shrink.Begin();
   _State = State.Minimized;
}

When the spButtons_MouseEnter event handler is called, the code checks to see if a field named _State has a value of State.Minimized. The _State field is an enum type that can hold Maximized or Minimized values and defaults to a value of State.Maximized. If the _State field is set to State.Minimized, then the Grow Storyboard shown earlier is started by calling its Begin() method. This has the effect of expanding the menu in the interface. The spButtons_MouseLeave event handler does the exact opposite and collapses the menu by calling the Shrink Storyboard's Begin() method.

The end result is that the user can see the header menu when the interface first loads. As they mouse over and back out of the menu, it's collapsed to a height of 14. When they mouse back over the menu, it expands to a height of 40 so that they can see all of the menu items.

Figure 2 shows an example of what the collapsed menu looks like (you might want "spiff" it up some and provide additional graphics so the user knows to mouse over the menu to expand it again).

That's all there is to it! There are other techniques, such as clipping, that can be used to perform the same overall effect but you can see that creating a flyout-style header menu is quite simple and involves a minimal amount of programming code.

About the Author

Dan Wahlin (Microsoft MVP for ASP.NET and XML Web Services) is the founder of The Wahlin Group which specializes in .NET and SharePoint onsite, online and video training and consulting solutions. Dan also founded the XML for ASP.NET Developers Web site, which focuses on using ASP.NET, XML, AJAX, Silverlight and Web Services in Microsoft's .NET platform. He's also on the INETA Speaker's Bureau and speaks at conferences and user groups around the world. Dan has written several books on .NET including "Professional Silverlight 2 for ASP.NET Developers," "Professional ASP.NET 3.5 AJAX, ASP.NET 2.0 MVP Hacks and Tips," and "XML for ASP.NET Developers." Read Dan's blog here.

comments powered by Disqus

Reader Comments:

Fri, May 4, 2012 Dennis South Africa

Sorry, this value was 14: if (spButtons.Height == 5)

Fri, May 4, 2012 Dennis South Africa

Instead of the "State" thing, I just used this and it works perfectly: private void spButtons_MouseEnter(object sender, MouseEventArgs e)
{
if (spButtons.Height == 5)
Grow.Begin();
}

private void spButtons_MouseLeave(object sender, MouseEventArgs e)
{
if (spButtons.Height == 40)
Shrink.Begin();
}

Fri, Feb 10, 2012 David SLC, Utah

This is a newbie question, but I wasn't able to find an answer. I understand everything in this article EXCEPT how you were able to get the state of your control. Can you help me out here?

Thu, Jan 5, 2012 subbu bangalore

its very good and nice and simple program.it helps lot to me Thanks Subbu

Sun, Feb 28, 2010 Chris

Dan has provided a perfectly useful tutorial. All the previous commenter can do is whinge about the ads. This is exactly the kind of brain dead, bed-sit bound crap head that people like me strive never to employ. Wise up.

Mon, Jan 18, 2010

you've got the same ad displayed 3 times in 3 different formats, and one of those formats is a horizontal banner where a skyscraper should be, it's extending over the article text

also, every silverlight tutorial should start with an interactive example of something interesting, embedded in the page

then you rant about how you made it

Add Your Comments Now:

Your Name:(optional)
Your Email:(optional)
Your Location:(optional)
Comment:
Please type the letters/numbers you see above

.NET Insight

Sign up for our newsletter.

I agree to this site's Privacy Policy.