I am trying to create a shiny loading spinner in WPF. It's supposed to have circles in a circles and it's supposed to spin, giving the user something to look at while I'm processing some data. Picture attached. You may notice that the actual result is somewhat low quality. That's because no matter what I try to do, the spinner takes about 5 to 7% CPU. This is not acceptable for me, since... well, it's a spinner. It spinns when the computer is busy doing something, and I frankly want it to do that something sooner rather than later.
(source: bayimg.com)Okay, so the XAML code defines two nested grids like so:
<Grid
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
x开发者_StackOverflowmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
x:Class="WPFTest.Spinner"
Name="View" Width="40" Height="40">
<Grid Name="Grid" Width="40" Height="40" >
<Grid.CacheMode>
<BitmapCache EnableClearType="False" RenderAtScale="1" SnapsToDevicePixels="False"/>
</Grid.CacheMode>
</Grid>
</Grid>
The rest is in the code-behind, basically adding a few ellipses and setting up the animation.
First my method that creates ellipses:
private static Ellipse GetEllipse(double x, double y, double opacity)
{
return new Ellipse
{
Fill = new SolidColorBrush(Colors.White),
Width = Size,
Height = Size,
Margin = new Thickness(x, y, 0, 0),
Opacity = opacity
};
}
The Spinner constructor
public Spinner()
{
InitializeComponent();
const double step = 2 * Math.PI / Count; //Cound is const = 8
const double r = 1.4 * Field; //Field is const = 40
double angle = 0;
for (var i = 0; i < Count; i++)
{
Grid.Children.Add(GetEllipse(r * Math.Cos(angle), r * Math.Sin(angle), 1 - i/(double) Count));
angle += step;
}
_doubleAnimation = new DoubleAnimation(0, 360, new Duration(new TimeSpan(0, 0, 1)))
{
RepeatBehavior = RepeatBehavior.Forever,
};
Grid.RenderTransform = new RotateTransform(0, Field, Field);
RenderOptions.SetBitmapScalingMode(this, BitmapScalingMode.NearestNeighbor); //Low quality!
Grid.RenderTransform.BeginAnimation(RotateTransform.AngleProperty, _doubleAnimation );
}
Now all this basically works, and it's even kinda pretty when you remove lines that set everything to low quality. But it's ultimately useless. If I'm loading something and this spinner takes 5-7% of my CPU, then it's a problem for me. Sure, multicore... whatever. No. This should work! :)
My next best idea of fixing this is instead of rotating the spinner, just reset the color of each individual ellipse after some interval. I'll try that eventually, but meanwhile it would be very interesting to know what's going on, and why such simple animation is taking forever. Also, if there is a "MakeAnimationWorkBetter" attribute I haven't set, I would be much obliged to find out where and how...
Thanks in advance.
You can reduce the framerate of animations via the TimeLine.DesiredFrameRate attached property:
<DoubleAnimation Storyboard.TargetProperty="Opacity" Duration="0:0:0.5"
From="1.0" To="0.5" Timeline.DesiredFrameRate="30" />
The default is 60fps.
Regards, Colin E.
Instead of using a rotate transform which is relatively expensive, why not change the opacity of the ellipses which is a much cheaper action?
Gilad.
精彩评论