Web Development Adventures in a .NET world

By Ola Karlsson

Building a simple animated menu with Silverlight 2 - Part 2

After mainly having used Expression Blend to build the XAML for our menu in part 1, it's now time to move back into Visual Studio and actually make some stuff happen :) The Finished result we're aiming for can be viewed here.

Update: I have updated the source code to work with Beta 2 and moved it to a different location, download the code here:  http://www.olakarlsson.com/Downloads.aspx

For this part I use Visual Studio 2008 and C#.

We'll use the solution from part 1, (Silverlight2MenuDemo) so open the solution from part 1 if you've not got it it can be downloaded from here, if you've already got it open in Blend you can right click the solution and select "Edit in Visual Studio".

The first thing we want to do is to edit our XAML a bit, open page.xaml and make the following changes. As with pretty much all XAML objects we could do the following changes with code but to keep it simple I'm going to add the animation objects in our XAML.

Start with adding a Storyboard, a storyboard is the basis of an animation for more in depth information about Animations in Silverlight check out the msdn resources on the topic. Notice how in Visual Studio, unlike in Blend you have full Intellisense for all your XAML, because of this it is often handy to draw up the initial XAML in Blend where you have access to drawing tools etc. but then switch to Visual Studio for fine tuning, just like we've done with our project.


A storyboard is counted as a  resource and is added as seen below. As with all our XAML objects that we wan't to access from code we have to give it an x:Name, I like to name things after what hey do so I've called it "NavigationStoryBoard"

image

Now we need an animation, inside the storyboard add a DoubleAnimation, I've called mine "navAnimation", I choose a DoubleAnimation purely for simplicity sake. As you will see later there are some limitations to what we can do with a Doubleanimation and in a real scenario it might not be the best choice. However for our little demo project it helps to keep things simple :)

image

Next thing we need to do is to tell our animation what object it's supposed to animate, we do this by adding a "Storyboard.TargetName" the object in this case is the red rectangle, which we named mySlider. We also need to tell the animation what property on the target object we're wanting to animate. This is done by adding a "Storyboard.TargetProperty" value, again for simplicity sake we'll just use the objects Canvas.Left property to make the red slider move back and forth between our Menu options. The result should look like below.
image

To finish off our animation we need to give it a duration, i.e. how long will it take for the animation to play. We do this by simply adding a "Duration" value. The Duration below is set to 0.5 of a second.
image

That's it for the XAML, now it's time to move on to the code.

As I'm no expert on XAML animations, I'm not saying that this is the perfect way of doing this but it seems to work ok for what we're doing here.
For controlling the animation, I decided to manipulate the To and From values in code.

The code for manipulating the animation and the storyboard is actually very simple, the somewhat more tricky bit is working out the logic.

The way I decided to tackle it is as follows, I use a number of variables

image

The variables HomePosition,APosition and BPosition are used to hold the values for the menu items positions.

currentlySelectedPosition is used to hold the value of which menu item was last clicked (i.e. where the slider is at the moment).

Next thing is to move inside the Page() code, by default there is a call to InitializeComponent(), this is a method which gives us references to the XAML object we have given x:Names.
If you hadn't noticed, the Page class is marked as partial, the InitializeComponent method is in another part of this class, the code is stored in a file called page.g.cs, the easiest way to find this file is to right click on the InitializeComponent method and select "Go to definition". when viewing this file keep in mind that it's automatically generated and any changes you make in here are likely to get overwritten.

image

Now that we have references to our XAML objects on the page we can set the values for our position variables.

I set the positions of the Menu items by getting the canvas.left value of the Menu option, then adding half of the actual width of the item to get the middle. However to get the middle of the slider to the middle of the menu item, we then subtract half
the width of the slider

HomePosition = (Convert.ToDouble(MenuItemHome.GetValue(Canvas.LeftProperty)) + (MenuItemHome.ActualWidth / 2) - mySlider.ActualWidth / 2);

Next in the Page() method we set up the event handlers we need, for each menu item we need a MouseEnter, a MouseLeave and a MouseLeftButtonUp event handler.

image

And finally we set the default values for the sliders start position, the LeftProperty and the currentlySelectedPosition .
As we're starting with the slider at the "Home" menu item we set it to the HomePosition.

image

Ok so now that we've finished setting things up,it's about time to see something happen!

The code for controlling the animation etc. is pretty much the same for all the menu item event handlers and could be re-factored out into their own methods but to keep it simple and more readable I've just keep the code in the handlers.

Let start with the MouseEnter event, obviously we have one for each menu item, here's the one for B

image

Basically we check that the slider isn't already at our current position, if it's not we move the slider from where it is (currentlySelectedPosition), to the menu item position which is being hovered over.

Lets have look at the MouseLeftButtonUp events, (we could just as easily use MouseLeftButtonDown but the Up event usually gives more of a clicking experience)

image

All we do here is to set the currentlySelectedPosition to the value of the position we're at, HomePosition, APostion and BPosition respectively. As we're clicking the menu item, the animation that runs on mouseEnter will already have completed and we just need to tell the app that the slider now is at position X...

To the final part of our code, the MouseLeave event, again we of course have one for for each menu item, here's the B option.

image 

Pretty much we're doing the same as on MouseEnter but in reverse.
We check that the option we've just left isn't the currently selected one because if it is we don't want to move the slider. However if the option we just left with the mouse, isn't the selected one then we want to move the slider back to the selected menu item.

Note:

This project is done in the simplest way I could think of. I wanted to use something a bit more interesting then a start and stop button to move a shape over the page. The aim is to show, at a beginner level how to use C# and .Net to control an animation in Silverlight 2. Being a simple demo project there are limitations, some of these include the following.

  • Using a basic DuobleAnimation makes the animation quite jerky, to get a smother animation you would probably use a animation with keyframes where you get a lot more control over the motion in the animation.
  • Also of course it's somewhat limiting when all the menu items have to be manually set up and and wired.

Possible enhancements:
As discussed, making the animation smoother.
Refactoring the code to make it more reusable and more dynamic.
Making the menu into a reusable control
Using the Silverlight menu in a .html or .aspx page controlling the html content.

I've been working on some of these enhancements and you can follow the progress here

Finally, the full source code for this demo can be downloaded here, any constructive feedback is more then welcome, hope you enjoyed  :)

Update: I have updated the source code to work with Beta 2 and moved it to a different location, download the code here:  http://www.olakarlsson.com/Downloads.aspx

Comments

No Comments