开发者

Performance Problems in Creating a Simple Loading Animation in WPF

开发者 https://www.devze.com 2023-01-31 02:02 出处:网络
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. Pict

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.

Performance Problems in Creating a Simple Loading Animation in WPF

(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.

0

精彩评论

暂无评论...
验证码 换一张
取 消

关注公众号