For a while now, I've been writing a Silverlight 2.0 game based on
Desktop Tower Defense. Recently I wanted to profile my code to look for any performance bottlenecks. I tried using Red-Gate's
ANTS Profiler but I couldn't get it to work with Silverlight. So after much searching online and a
post on the Silverlight forums, it was suggested that I should convert it to WPF. I followed
this post from Scott Gu, but found several (as far as I know) undocumented differences between Silverlight 2.0 and WPF that I wanted to share:
Storyboards1. Change
x:Name= to
x:Key=Storyboards in WPF are stored in a Resources dictionary and indexed by a Key rather than a Name.
2. Change
this.story1 to
(Storyboard)this.Resources["story1"]For some reason WPF doesn't generate local properties for your storyboards, like Silverlight does. A storyboard with x:Name="story1" in Silverlight would create the this.story1 property. In WPF you have to look up all your storyboards from this.Resources using (Storyboard)this.Resources["story1"].
3. Change
Storyboard.SetTarget(story1, canvas1) to
Storyboard.SetTargetName(story1, "canvas1")Sometimes you have to manually set the target of an animation in code. In Silverlight you can pass the actual element (i.e. canvas1), in WPF you can only specify the name. This means you must set the x:Name for any element you want as the target of an animation....not terribly convenient.
4. Make sure
Storyboard.TargetProperty="(RotateTranform.Angle)" have
(parens)I often manually tweak my animation XAML. In Silverlight you can get away with Storyboard.TargetProperty="RotateTransform.Angle" in WPF you need the parens.
Animations5. Change
this.animation1 to
(DoubleAnimation)((Storyboard)this.Resources["story1"].Children[0])Similar to Storyboards, Animations have to be referenced through its Storyboard's Children collection. Even if you add a x:Name="animation1" to the Animation, WPF won't generate a local property for you. Of course you could manually create one as well.
6. Change
Begin() to
Begin(this) and
Stop() to
Stop(this)WPF has several overrides for Begin and Stop, but for some reason doesn't have a plain signature like Silverlight.
Namespaces7. Change
xmlns:my="clr-namespace:MyNamespace;assembly=MyAssembly" to
xmlns:my="clr-namespace:MyNamespace"WPF doesn't require the assembly references, I wish Silverlight didn't either.
8. Remove any
using System.Windows.Browser;Only needed for Silverlight apps.
Application9. Remove references to
this.HostWhile obvious in hindsight, at first this one threw me. In WPF there's no such thing as a SilverlightHost object. Since the App() constructor was a logical place to configure the Host, I needed to remove these references:
public App()
{
this.Host.Settings.MaxFrameRate = 25;
this.Host.Settings.EnableFrameRateCounter = true;InitializeComponent();
}
Note: there's also no such thing as MaxFrameRate or EnableFrameRateCounter in WPF. I guess when it's a local app you can go hog wild. :D 10. Change
UnhandledException to
DispatcherUnhandledExceptionWPF uses a different event for unhandled exceptions:
public App()
{
this.UnhandledException += this.Application_UnhandledException;
}
public App()
{
this.DispatcherUnhandledException += this.Application_UnhandledException;
}
11. Change
this.RootVisual = new Page() to
StartupUri="Page.xaml"The App's Startup event is where the RootVisual is generally set. This should be replaced with the StartupUri tag in App.Xaml. Why does Silverlight use RootVisual and WPF uses a StartupUri? Good question.
12. Change
App.Current.RootVisual to
App.Current.MainWindowSometimes you need to get to the main page\window from a user control or elsewhere. WPF and Silverlight does this differently.
Miscellaneous13. Explicitly set
Canvas.Top=0 when using
Canvas.GetTop(canvas1)In XAML, often times I wouldn't put Canvas.Top=0 or Canvas.Left=0 for brevity sake. However in code, I later would ask for Canvas.GetTop(canvas1). In Silverlight this works as I would expect, and returns a 0 (double), but in WPF this returns an invalid number (NaN). Setting the Canvas.Top=0 in the XAML on canvas1 resolved this. This is also true if you use (double)canvas1.GetValue(Canvas.TopProperty);
14. Don't set
TextBlock.Foreground.ColorIn Silverlight you can do ((SolidColorBrush)textblock1.Foreground).Color = Color.FromArgb(255, 255, 0, 0). In WPF you will get a Invalid Operation Exception with a read-only state error. Why, I don't know.
15.
ContentPresenter schema is different
In Silverlight you can use the following tags for a ControlTemplate's ContentPresenter, in WPF you cannot:
TextWrapping=
Foreground=
FontSize=
HorizontalContentAlignment=
VerticalContentAlignment=
Well after all that I was then able to successfully compile and run the WPF app with ANTS Profiler. Yahoo! I plan to share any lessons learned from profiling in a future post.