WPF: Ruckelfreier Ladebalken/Fortschrittsbalken ohne Sprünge


Habe mich heute daran gesetzt einen kontinuierlichen Fortschrittsbalken für WPF zu erstellen. Dabei habe ich einfach die Klasse der normalen ProgressBar überschrieben. Anstelle von "Value" sollte man "TargetValue" verwenden. Wer möchte kann natürlich auch "Value" von der Basisklasse überschreiben.
Das Property "Acceleration" kann dazu benutzt werden die Geschwindigkeit der Bewegung anzupassen. Der Ladebalken hat dabei immer eine konstant beschleunigte oder negativ beschleunigte Bewegung. Hier könnte man natürlich beliebige Kurven verwenden, wie etwa eine Parabel. Ich denke jedoch, dass es so schon relativ smooth aussieht.


using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Timers;
using System.Windows.Media;
using System.Windows.Threading;

namespace progressbar
{
    class ProgressBar : System.Windows.Controls.ProgressBar
    {
        private Timer _drawTimer;
        private double _speed;
        public new double Value { get; set; }
        public double Acceleration { get; set; }  

        public ProgressBar()
        {
            _drawTimer = new Timer();
            _drawTimer.Elapsed += new ElapsedEventHandler(OnTimerEvent);

            // 25 Fps für Timer verwenden
            _drawTimer.Interval = 40;
            _drawTimer.Enabled = true;

            _speed = 0;
            Acceleration = 1;
            Value = 0;
        }

        public void OnTimerEvent(object source, ElapsedEventArgs e)
        {
            // Dispatcher aufrufen um an STA-Thread von wpf zu gelangen
            Dispatcher.Invoke( DispatcherPriority.Normal, (Action)delegate()
            {
                if (Value != base.Value)
                {
                    // beliebiges maximum normalisieren
                    double faktor = 1 / Maximum;
                    // position auf Interval von 0-1 berechnen
                    double position = faktor * base.Value;

                    // Minimum berechnen zwischen beschleunigter und negativ beschleunigter Bewegung
                    // parameter 1: v = a*t
                    // parameter 2: v = sqrt(2*Bremsweg*a)
                    _speed = Math.Min(_speed + Acceleration * (_drawTimer.Interval / 1000),
                        Math.Sqrt(2 * Math.Abs((faktor * Value) - position) * Acceleration));

                    // Nach rechts oder Links bewegen. s = v * t
                    if (Value > base.Value)
                    {
                        position += (_drawTimer.Interval / 1000) * _speed;
                        base.Value = Math.Min(position / faktor, Value);
                    }
                    else
                    {
                        position -= (_drawTimer.Interval / 1000) * _speed;
                        base.Value = Math.Max(position / faktor, Value);
                    }
                }
            });
        }
    }
}
Bookmark and Share

1 Kommentare:

Anonym hat gesagt…

Einer von nicht all zu vielen deutsche WPF Blogs. Dein Beitrag gefällt mir :) Mit der ProgressBar lassen sich generell mit WPF viele tolle Dinge anstellen. Ich bin übrigens auch seit kurzem wieder dabei WPF Posts zu verfassen:
WPF Blog

Kommentar veröffentlichen