Wow…there’s a lot of great software out there for mobile devices! Over the years I’ve purchased a lot of Windows Mobile programs but I’ve never looked at iPhone software since I didn’t have a compatible device. Over the holiday break I had the chance to play around with an iPod Touch as well as my HTC Touch Pro Windows Mobile phone more. Here’s some software that really impressed me.
Microsoft just released an update to the Silverlight 2 DataGrid that fixes the following issues:
Animations are a key part of Silverlight 2 that allow your applications to stand out from all of the boring and dull applications floating around on the Web. In previous articles I’ve written about storyboards and animations but as a quick review, Silverlight relies upon a Storyboard element to define several different types of animations such as DoubleAnimation (which animates object properties of type double) and ColorAnimation (which animates color properties). In this article I’ll show you how Silverlight can be used to create animations programmatically and how you can interact with animations defined declaratively in a XAML file using C#.
For this example I’ll create a simple “lightbox” style container that can display pictures from Flickr. As the picture is being shown the box will grow from a height/width of 0 to a larger size that’s determined by the size of the browser. Three different animations will be performed by the image display container:
- Animate the Width from 0 to the width of the browser / 1.5
- Animate the Height from 0 to the height of the browser / 1.5
- Animate the Opacity from 0 to 1
If you know the To and From values of the animations upfront then it’s easiest to define them in the XAML file. In cases where there’s an unknown animation property value, you can create the storyboard and animation objects programmatically or update properties of an existing Storyboard defined in XAML. In this case a Border control will be animated:
<Border x:Name="LightBoxControl" BorderBrush="Black" BorderThickness="3" CornerRadius="10" Height="20" Width="20" Opacity="0" Margin="5" MouseLeftButtonDown="Image_MouseLeftButtonDown"> <Border.Background> <LinearGradientBrush EndPoint="0.893,0.116" StartPoint="0.403,0.694"> <GradientStop Color="#FFB9B9B9" Offset="1"/> <GradientStop Color="#FF4F4F4F" Offset="0"/> <GradientStop Color="#FF666666" Offset="0.496"/> </LinearGradientBrush> </Border.Background> <StackPanel x:Name="spImage"> <Border HorizontalAlignment="Right" VerticalAlignment="Top" BorderBrush="Black" BorderThickness="1" CornerRadius="8" Background="LightGray" Width="60" Height="25"> <TextBlock HorizontalAlignment="Center" VerticalAlignment="Center" FontSize="12" Text="Close" /> </Border> <Rectangle x:Name="LightBoxImage" HorizontalAlignment="Center" Fill="Black" RadiusX="10" RadiusY="10" Stroke="LightGray" StrokeThickness="2" Margin="5"> </Rectangle> </StackPanel> </Border>
Here’s an example of programmatically creating a Storyboard and defining the 3 animations mentioned earlier to change the Width, Height and Opacity properties of the Border control:
double? width = (double?)System.Windows.Browser.HtmlPage.Document.Body.GetProperty("offsetWidth") / 1.5; double? height = (double?)System.Windows.Browser.HtmlPage.Document.Body.GetProperty("offsetHeight") / 1.5; //Programmatic way to create a storyboard and animations Storyboard sb = new Storyboard(); //Create animation for Border control's Width DoubleAnimation wa = new DoubleAnimation(); wa.Duration = new Duration(TimeSpan.FromSeconds(0.5)) wa.From = 0; wa.To = width; Storyboard.SetTarget(wa, LightBoxControl); Storyboard.SetTargetProperty(wa, new PropertyPath(Border.WidthProperty)); sb.Children.Add(wa); //Create animation for Border control's Height DoubleAnimation ha = new DoubleAnimation(); ha.Duration = new Duration(TimeSpan.FromSeconds(0.5)); ha.From = 0; ha.To = height; Storyboard.SetTarget(ha, LightBoxControl); Storyboard.SetTargetProperty(ha, new PropertyPath(Border.HeightProperty)); sb.Children.Add(ha); //Create animation for Border control's Opacity DoubleAnimation oa = new DoubleAnimation(); oa.Duration = new Duration(TimeSpan.FromSeconds(0.5)); oa.From = 0; oa.To = 1; Storyboard.SetTarget(oa, LightBoxControl); Storyboard.SetTargetProperty(oa, new PropertyPath(Border.OpacityProperty)); sb.Children.Add(oa); this.spImage.Width = width.Value - 30; this.spImage.Height = height.Value - 30; this.LightBoxImage.Width = width.Value - 75; this.LightBoxImage.Height = height.Value - 75; sb.Begin();
In this example the final height and width of the target Border control are determined by grabbing the offsetWidth and offsetHeight values using the HtmlPage class. Once those values are determined a Storyboard object is created along with the three animations all of type DoubleAnimation. Each animation takes 1/2 second to complete and animates the Border control’s Height, Width and Opacity properties respectively.
Looking through the code for each animation object you’ll notice that it is associated with the target object and target object property using the Storyboard.SetTarget() and Storyboard.SetTargetProperty() static methods respectively. This may seem strange at first glance but makes sense once you understand the concept of attached properties. Each animation object is added to the parent Storyboard object using the Children.Add() method and the Storyboard is started by calling the Begin() method.
Interacting with Storyboards and Animations Defined in XAML
The programmatic approach to creating animations works great when there’s a lot of dynamic data being fed into animation objects. However, in this example only the Height and Width properties are being changed on the Border control. That’s a lot of code to write to change two properties. Rather than defining everything programmatically you can instead define the storyboard and associated animations declaratively and fill in the dynamic pieces at runtime. Here’s an example of defining the 3 animations shown earlier in XAML:
<Storyboard x:Name="sbShow"> <DoubleAnimation x:Name="daWidth" Storyboard.TargetName="LightBoxControl" Storyboard.TargetProperty="Width" From="0" Duration="00:00:0.5" /> <DoubleAnimation x:Name="daHeight" Storyboard.TargetName="LightBoxControl" Storyboard.TargetProperty="Height" From="0" Duration="00:00:0.5" /> <DoubleAnimation Storyboard.TargetName="LightBoxControl" Storyboard.TargetProperty="Opacity" From="0" To="1" Duration="00:00:0.5" /> </Storyboard>
Before the storyboard starts to play the To property of the daWidth and daHeight objects can then be assigned values as shown next:
double? width = (double?)System.Windows.Browser.HtmlPage.Document.Body.GetProperty("offsetWidth") / 1.5; double? height = (double?)System.Windows.Browser.HtmlPage.Document.Body.GetProperty("offsetHeight") / 1.5;
//Define how big the Border control should be animated to by setting the To property value
this.daWidth.To = width; this.daHeight.To = height;
this.spImage.Width = width.Value - 30; this.spImage.Height = height.Value - 30; this.LightBoxImage.Width = width.Value - 75; this.LightBoxImage.Height = height.Value - 75;
And that’s all there is to it! Silverlight makes it easy to work with dynamic animations whether programmatically or through modifying storyboards defined in XAML. Download a working version of the Flickr lightbox application here if you’d like to see the animations in action (as well as some others).
Every now and then I blog about non-techie topics since there’s a lot going on in the world besides code. In a previous post I wrote about “know it all” people and a new song called Learning to Fall that my son and I wrote about them. This post covers a different topic.
Over the weekend I went to Disneyland with my wife and two boys. A few weeks back my wife had knee surgery that she’s still recovering from. She’s unable to walk around a lot and using crutches while navigating through the crowds at Disneyland wouldn’t work too well. As a result, we got her a wheel chair and my kids took turns pushing her around from ride to ride. While I thought we should just stay home, my wife’s a Disneyland fanatic, really tough and wanted to go since it’s a tradition to go near my oldest son’s birthday.
With a wheel chair you have to go through specific entrances and exits to get on and off the rides. You also have to navigate through the crowds which were fairly large on Saturday. We had a lot of experience pushing strollers through crowds when the kids were young but we didn’t have to worry about people bumping a knee or anything so it was different this time around.
As we pushed my wife around the first thing I noticed was the number of people with wheel chairs and canes in the park. I’ve always noticed a few when we went in the past, but this time my focus changed I guess since we were in the same situation. There were a lot more disabled people than I realized once I started looking more closely. I also noticed that a lot of people completely ignore people in wheel chairs, with canes, etc. Few times did anyone offer to help open a door as we were trying to get through an entrance or move out of the way as we tried to go through a wheel-chair specific opening in a line. While going to the Indiana Jones ride we had to wait for a group of 20+ people to go through the wheel chair section of the ramp while we waited. They could have gone through the other smaller sections designed for people that could walk OK but they didn’t. People basically ignored the chair and the person in it. We didn’t expect them to do anything specific of course, but some people were just plain oblivious, clueless and rude. It was an eye-opening experience into what people with permanent disabilities must deal with on a daily basis. There were of course some people that did take a moment to help with a door, but not nearly as many as I would’ve expected.
The bright spot was the Disneyland staff. I have to say that on every single ride the staff was extremely helpful and the majority of them were very friendly. I was extremely impressed with how well my wife was treated and have to commend Disney for the training they gave their employees.
Lesson Learned: Open your eyes and be more helpful to people with disabilities. It’s easy to ignore or treat people differently when they’re not exactly like you but if you think about it that’s completely ridiculous. People are people….some just have more difficult problems to deal with in life. While my family’s experience in the disabled world was very temporary, I’m hopeful that we all learned that it’s important to take time to help people out. Life’s too short to be constantly rushing everywhere.