Charles Petzold



“Gretchen am Spinnrade” (the Silverlight version)

November 20, 2008
New York, N.Y.

Here's a Silverlight version of the WPF program I discussed two weeks ago that displays the score of Schubert's song “Gretchen am Spinnrade” (“Gretchen at the Spinning Wheel”) synchronized to a video of a talented young singer named Emily:


GretchenAmSpinnrade.html

The source code (GretchenAmSpinnrade.zip) includes a 3 meg PNG file of the score and a 3 meg WMV file of the video. Most of the files in the two projects are generated by Visual Studio. The only files that contain my code are Page.xaml and Page.xaml.cs in the GretchenAmSpinnrade project. In the GretchenAmSpinnrade.Web project, the PNG and WMV files are in a Media subdirectory of the customary ClientBin.

Converting the code from WPF to Silverlight provoked the usual gnashing of teeth and then some. The ClipToBounds property is absent from Silverlight (although in this case it was easily mimicable with the Clip property). You can't use IsAdditive with animations, or SourceName with an EventTrigger.

As you may recall, I had problems with the original all-XAML WPF version because I needed to prevent the video from playing before the bitmap was entirely loaded. In the Silverlight version, I decided to keep the Page.xaml file very simple and perform all the loading of the PNG file and WMV file in code. I did away with the EventTrigger entirely and moved the whole Storyboard to a resource. All the bindings and styles and triggers are gone from the XAML file, but it now has a simple ProgressBar

The Page.xaml.cs file initiates downloading of the bitmap in the class's constructor. It creates a BitmapImage object, sets a handler for the DownloadProgress event, sets the UriSource to "Media/GretchenAmSpinnrade.png", and sets the Source property of the Image element in the XAML file to this BitmapImage.

The DownloadProgress event handler updates the ProgressBar. When the bitmap is entirely loaded, the Source property of the MediaElement is set to the URI "Media/GretchenAmSpinnrade.wmv", and the animation storyboard is started to animate the bitmap. Both URI's are relative to the ClientBin directory containing the GretchenAmSpinnrade.xap file.

But before I got the loading sequence working, I had trouble with the actual WMV video. The WPF MediaElement handled it fine, but the Silverlight MediaElement thought it had a format error. Could it have been the variable bit rate? I used the Windows Movie Maker to convert the file to a "Windows Media Low Bandwidth (117 kbps)" format, and that version worked OK with the Silverlight MediaElement.

I also had trouble with the PNG file. I know that an image that is 32,570 pixels wide is dangerously close to the magic 216 limit that causes all sorts of problems with bitmaps, but it worked OK in WPF. In the Silverlight version, I couldn't get it to do precisely what I wanted. To be consistent with the WPF program, I wanted the first DiscreteDoubleKeyFrame in the animation to have a Value of 312, and the second to also have a Value of 312 and a KeyTime of 0:0:3.5, but if you make those changes in the source code, you'll find that the bitmap never appears! It's as if these values are being added to the actual width of the bitmap, and the result is baffling some code. I also tried to mimic this offset with a RenderTransform and a Margin applied to the Image and the Canvas parent to the Image and in all cases the bitmap also disappeared from view.

I don't know about you, but the idea that WPF and Silverlight have different MediaElement's and different bitmap-handling logic makes me very nervous.