0

Below is a small graphics demo in WPF. It looks something like this:

enter image description here

When it's running, if I move the mouse around the main area of the window, the animation slows down (at least on my system). If I move the mouse pointer out of the window entirely, the animation come back up to speed.

Any suggestions for how to prevent the mouse movement interfering with the animation speed?

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using System.Threading;
using System.Windows.Threading;

namespace WPF_Golden_Section
{
    class DrawingVisualElement : FrameworkElement
    {
        public DrawingVisual visual;

        public DrawingVisualElement() { visual = new DrawingVisual(); }

        protected override int VisualChildrenCount { get { return 1; } }

        protected override Visual GetVisualChild(int index) { return visual; }
    }

    public static class CanvasUtils
    {
        public static Canvas SetCoordinateSystem(this Canvas canvas, Double xMin, Double xMax, Double yMin, Double yMax)
        {
            var width = xMax - xMin;
            var height = yMax - yMin;

            var translateX = -xMin;
            var translateY = height + yMin;

            var group = new TransformGroup();

            group.Children.Add(new TranslateTransform(translateX, -translateY));
            group.Children.Add(new ScaleTransform(canvas.ActualWidth / width, canvas.ActualHeight / -height));

            canvas.RenderTransform = group;

            return canvas;
        }
    }

    public static class ColorUtils
    {
        public static Color Write(this Color color)
        {
            Console.Write("Color[{0} {1} {2} {3}]", color.A, color.R, color.G, color.B);

            return color;
        }

        static byte ColorComponentToByte(double n)
        {
            return 
                (byte)
                    Math.Round(Math.Min(Math.Max(n, 0), 1) * 255);
        }

        public static Color Rgb(double r, double g, double b)
        {
            return
                Color.FromRgb(
                    ColorComponentToByte(r),
                    ColorComponentToByte(g),
                    ColorComponentToByte(b));
        }

        public static Color SetArgb(this Color color, double a, double r, double g, double b)
        {
            color.A = ColorComponentToByte(a);
            color.R = ColorComponentToByte(r);
            color.G = ColorComponentToByte(g);
            color.B = ColorComponentToByte(b);

            return color;
        }
    }

    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();

            Width = 600;
            Height = 600;

            var dockPanel = new DockPanel();

            Content = dockPanel;

            var slider =
                new Slider()
                {
                    Minimum = 0.1,
                    Maximum = 10,
                    LargeChange = 0.001,
                    Value = 1
                };

            dockPanel.Children.Add(slider);

            DockPanel.SetDock(slider, Dock.Top);

            var incrementSlider =
                new Slider()
                {
                    Maximum = 0.001,
                    Minimum = 0.00001,
                    Value = 0.0001
                };

            dockPanel.Children.Add(incrementSlider);


            DockPanel.SetDock(incrementSlider, Dock.Top);

            var pauseButton = new Button() { Content = "Pause" };

            dockPanel.Children.Add(pauseButton);

            DockPanel.SetDock(pauseButton, Dock.Top);

            var canvas = new Canvas();

            dockPanel.Children.Add(canvas);

            DockPanel.SetDock(canvas, Dock.Top);

            SizeChanged += (s, e) => canvas.SetCoordinateSystem(-400, 400, -400, 400);

            var element = new DrawingVisualElement();

            Action draw = () =>
                {
                    canvas.Children.Clear();

                    // var element = new DrawingVisualElement();

                    using (var dc = element.visual.RenderOpen())
                    {
                        for (var i = 0.0; i < 720.0; i += slider.Value)
                        {
                            var radius = Math.Sin(i / 720.0 * Math.PI) * 30;

                            var phi = (1 + Math.Sqrt(5)) / 2;

                            var omega = 2 * Math.PI * (phi - 1) * i;

                            var x = Math.Cos(omega) * 0.5 * i;
                            var y = Math.Sin(omega) * 0.5 * i;

                            dc.DrawEllipse(
                                new SolidColorBrush(ColorUtils.Rgb(i / 360.0, i / 360.0, 0.25)),
                                new Pen(Brushes.Black, Math.Max(radius / 6, 1)),
                                new Point(x, y),
                                radius / 2,
                                radius / 2);
                        }
                    }

                    canvas.Children.Add(element);
                };

            slider.ValueChanged += (s, e) =>
            {
                Title = slider.Value.ToString() + "     " + incrementSlider.Value;
                draw();
            };

            var timer = new DispatcherTimer();

            timer.Tick += (s, e) =>
                {
                    if (slider.Value < 10.0)
                        slider.Value += incrementSlider.Value;
                };

            timer.Start();

            pauseButton.Click += (s, e) =>
                {
                    if (timer.IsEnabled)
                        timer.Stop();
                    else
                        timer.Start();
                };

            slider.Value = 3.5;
            incrementSlider.Value = 0.00001;
        }
    }
}
4

2 回答 2

3

如果您在 WPF 中使用第三个 Animation 选项,CompositionTarget.Rendering 事件,那么我发现没有减速。我已经从带有slider.ValueChanged的行中调整了示例中的代码:

        slider.Value = 3.5;
        incrementSlider.Value = 0.00001;

        EventHandler renderer = (s, e) =>
        {
            if (slider.Value < 10.0)
                slider.Value += incrementSlider.Value;

            //Title = slider.Value.ToString() + "     " + incrementSlider.Value;
            draw();
            _frameCounter++;
        };

        CompositionTarget.Rendering += renderer;
        pauseButton.Click += (sender, args) => CompositionTarget.Rendering -= renderer;

        var timer = new DispatcherTimer();
        timer.Interval = TimeSpan.FromMilliseconds(1000);
        timer.Tick += (s, e) =>
                          {
                              Title = string.Format("fps: {0}", _frameCounter);
                              _frameCounter = 0;
                          };

        timer.Start();

除非机器负载很重,否则 CompositionTarget.Rendering 会以固定的 60 fps 速率触发。您可以在 Internet 上找到代码来调整丢帧并避免明显的减速。

由于您的示例中的鼠标活动导致减速,我没有很好的解释。我的第一个想法是它是路由事件的瓶颈,但是通过从 ValueChanged 事件中提取 draw 方法来调整计时器间隔或重构似乎并没有解决问题。

顺便说一句,我喜欢你的样品。

于 2012-11-08T07:30:39.060 回答
0

可能是命中测试。您可以尝试在 Canvas 上将IsHitTestVisible设置为 false。

于 2012-11-07T02:13:59.723 回答