In our app, we have some scrolling credits in a ChildWindow. When showing this window, our CPU utilization is very high. The text is using a BitmapCache and hardware acceleration is enabled. Even after removing the clipping rectangle and the drop shadow from the child window, the CPU usage climbs to 80-90%. When I enable redraw region visualization, I see that only the scrolling text is getting redrawn, so I’m unsure why the CPU is going crazy. I tried animating both Canvas.Top and the TranslateY property of a CompositeTransform to do the scrolling.
Any ideas as to what may be causing this animation to be so expensive? Are there any good articles out there that have recommendations for optimizing animations in general? Here’s my XAML:
<c:ChildWindow xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:c="clr-namespace:System.Windows.Controls;assembly=System.Windows.Controls" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
x:Class="OurNamespace.UI.Views.AboutWindow"
Title="About Our App" Width="575"
Height="330" Style="{StaticResource ChromelessChildWindowStyle}"
mc:Ignorable="d"
MouseRightButtonDown="ChildWindow_MouseRightButtonDown"
Background="Black">
<Grid x:Name="LayoutRoot" CacheMode="BitmapCache">
<Grid.Triggers>
<EventTrigger RoutedEvent="Canvas.Loaded">
<BeginStoryboard>
<Storyboard Storyboard.TargetName="CreditsTransform"
Storyboard.TargetProperty="TranslateY">
<DoubleAnimation To="-750" RepeatBehavior="Forever"
Duration="0:0:30"/>
</Storyboard>
</BeginStoryboard>
</EventTrigger>
</Grid.Triggers>
<Image HorizontalAlignment="Left" VerticalAlignment="Top"
Source="/Assets/Graphics/SplashAbout/OurBackground.png"/>
<Grid Height="150" Width="570" HorizontalAlignment="Right"
Margin="0,0,0,80" VerticalAlignment="Bottom">
<Grid.RowDefinitions>
<RowDefinition Height="30"/>
<RowDefinition/>
</Grid.RowDefinitions>
<TextBlock x:Name="AppVersionTextBlock" Margin="10,0"
VerticalAlignment="Center" FontFamily="Arial"
FontSize="12" Foreground="White"
Text="{Binding VersionInfo, FallbackValue=Version 2.0.0}"
TextWrapping="Wrap"/>
<TextBlock x:Name="FirmwareVersionTextBlock" Margin="10,0"
VerticalAlignment="Center" FontFamily="Arial" FontSize="12"
Foreground="White" Text="{Binding FirmwareVersion.Value, FallbackValue=Firmware Version 1.0.0}"
TextWrapping="Wrap"
Visibility="{Binding FirmwareVersionVisibility.Value}"
TextAlignment="Right"/>
<Canvas Margin="0" Grid.Row="1" x:Name="Viewport">
<Canvas.Clip>
<RectangleGeometry Rect="0,0,575,120"/>
</Canvas.Clip>
<TextBlock FontFamily="Arial" FontSize="12" Width="555"
Foreground="White" TextWrapping="Wrap" Canvas.Left="10"
Text="{Binding Credits}" x:Name="Credits"
TextAlignment="Center" RenderTransformOrigin="0.5,0.5">
<TextBlock.RenderTransform>
<CompositeTransform TranslateY="0" x:Name="CreditsTransform"/>
</TextBlock.RenderTransform>
<TextBlock.CacheMode>
<BitmapCache/>
</TextBlock.CacheMode>
</TextBlock>
</Canvas>
</Grid>
<TextBlock Foreground="White" Text="{Binding CopyrightInfo, FallbackValue=© 2010 Our Company}"
TextWrapping="Wrap" Width="413" FontSize="10"
FontFamily="Arial" Height="44" HorizontalAlignment="Right"
Margin="0,0,30,21" VerticalAlignment="Bottom"/>
<Button x:Name="CancelButton" Width="575" Height="330" Opacity="0"
Click="CancelButton_Click" HorizontalAlignment="Right"
Margin="0" VerticalAlignment="Bottom"/>
</Grid>
</c:ChildWindow>
Update:
The CPU problem was not directly related to the ChildWindow itself but to the DropShadowEffect objects underneath which Silverlight was wastefully re-rendering. I’ve added an answer to describe how I worked around this.
When animating text in Silverlight you should be setting the TextHintingMode attached property to “Animated” on your TextBlock. To improve text readability Silverlight usually uses hinting to smooth each text glyph. This can have a large performance impact when animating text, since a change will cause recalculation of how the glyph is most legible which could be happening up to 60 frames a second with in an animation.
If that does not solve your problem I would recommend you start debugging performance with XPerf. There is a good tutorial on using this command-line tool to see where most of your CPU time is spent while a portion of your Silverlight application runs. You should be paying attention to how much CPU time is spent in agcore.dll, npctrl.dll, and coreclr.dll. If your performance problems are related to redrawing, most of the CPU time is likely spent in agcore.dll since that does most of the graphics related work for Silverlight. You can then drill into that and see the specific functions in agcore.dll that are getting called most often during your sample time. This can often help you realize which portions of your code are causing the performance hit and how you can optimize.