Gewusst wie: Rendern in Pro-Frame-Intervallen mit CompositionTarget
Das WPF-Animationsmodul stellt zahlreiche Features zum Erstellen framebasierter Animationen bereit. In manchen Anwendungsszenarios müssen Sie das Rendering jedoch auf Pro-Frame-Basis steuern können. Das CompositionTarget-Objekt bietet die Möglichkeit, benutzerdefinierte Animationen auf der Grundlage von Pro-Frame-Rückrufen zu erstellen.
CompositionTarget ist eine statische Klasse, die die Anzeigeoberfläche darstellt, auf der die Anwendung gezeichnet wird. Das Rendering-Ereignis wird jedes Mal ausgelöst, wenn die Szene der Anwendung gezeichnet wird. Die Rendering-Framerate gibt an, wie häufig die Szene pro Sekunde gezeichnet wird.
Hinweis |
---|
Ein vollständiges Codebeispiel für CompositionTarget finden Sie unter Beispiel für die Verwendung von CompositionTarget. |
Beispiel
Das Rendering-Ereignis wird während des WPF-Renderingprozesses ausgelöst. Im folgenden Beispiel wird gezeigt, wie Sie einen EventHandler-Delegaten bei der statischen Rendering-Methode für CompositionTarget registrieren.
' Add an event handler to update canvas background color just before it is rendered.
AddHandler CompositionTarget.Rendering, AddressOf UpdateColor
// Add an event handler to update canvas background color just before it is rendered.
CompositionTarget.Rendering += UpdateColor;
Mit der Rendering-Ereignishandlermethode können Sie benutzerdefinierten Zeichnungsinhalt erstellen. Diese Ereignishandlermethode wird einmal pro Frame aufgerufen. Immer wenn WPF die beibehaltenen Renderingdaten in der visuellen Struktur für die Szenengrafik der Komposition marshallt, wird die Ereignishandlermethode aufgerufen. Zudem wird die Ereignishandlermethode aufgerufen, wenn durch Änderungen an der visuellen Struktur Aktualisierungen der Szenengrafik erzwungen werden. Beachten Sie, dass die Ereignishandlermethode aufgerufen wird, nachdem das Layout berechnet wurde. Sie können das Layout jedoch in der Ereignishandlermethode ändern. In diesem Fall wird das Layout vor dem Rendern nochmals berechnet.
Im folgenden Beispiel wird gezeigt, wie Sie in einer CompositionTarget-Ereignishandlermethode benutzerdefinierte Zeichnungen bereitstellen können. In diesem Fall wird die Hintergrundfarbe von Canvas mit einem Farbwert erstellt, der auf der Koordinatenposition der Maus basiert. Wenn Sie die Maus innerhalb von Canvas, bewegen, ändert sich die Hintergrundfarbe. Darüber hinaus wird die durchschnittliche Framerate auf Basis der verstrichenen Zeit und der Gesamtanzahl gerenderter Frames berechnet.
' Called just before frame is rendered to allow custom drawing.
Protected Sub UpdateColor(ByVal sender As Object, ByVal e As EventArgs)
If _frameCounter = 0 Then
' Starting timing.
_stopwatch.Start()
End If
_frameCounter = _frameCounter + 1
' Determine frame rate in fps (frames per second).
Dim frameRate As Long = CLng(Fix(_frameCounter / Me._stopwatch.Elapsed.TotalSeconds))
If frameRate > 0 Then
' Update elapsed time, number of frames, and frame rate.
myStopwatchLabel.Content = _stopwatch.Elapsed.ToString()
myFrameCounterLabel.Content = _frameCounter.ToString()
myFrameRateLabel.Content = frameRate.ToString()
End If
' Update the background of the canvas by converting MouseMove info to RGB info.
Dim redColor As Byte = CByte(_pt.X / 3.0)
Dim blueColor As Byte = CByte(_pt.Y / 2.0)
myCanvas.Background = New SolidColorBrush(Color.FromRgb(redColor, &H0, blueColor))
End Sub
// Called just before frame is rendered to allow custom drawing.
protected void UpdateColor(object sender, EventArgs e)
{
if (_frameCounter++ == 0)
{
// Starting timing.
_stopwatch.Start();
}
// Determine frame rate in fps (frames per second).
long frameRate = (long)(_frameCounter / this._stopwatch.Elapsed.TotalSeconds);
if (frameRate > 0)
{
// Update elapsed time, number of frames, and frame rate.
myStopwatchLabel.Content = _stopwatch.Elapsed.ToString();
myFrameCounterLabel.Content = _frameCounter.ToString();
myFrameRateLabel.Content = frameRate.ToString();
}
// Update the background of the canvas by converting MouseMove info to RGB info.
byte redColor = (byte)(_pt.X / 3.0);
byte blueColor = (byte)(_pt.Y / 2.0);
myCanvas.Background = new SolidColorBrush(Color.FromRgb(redColor, 0x0, blueColor));
}
Möglicherweise stellen Sie fest, dass die benutzerdefinierte Zeichnung auf verschiedenen Computern mit unterschiedlicher Geschwindigkeit ausgeführt wird. Das liegt daran, dass die benutzerdefinierte Zeichnung von der Framerate abhängt. Je nach Betriebssystem und Arbeitslast wird das Rendering-Ereignis pro Sekunde unterschiedlich oft aufgerufen. Informationen zur Ermittlung der Grafikleistung eines Geräts, auf dem eine WPF-Anwendung ausgeführt wird, finden Sie unter Renderingebenen für Grafiken.
Das Hinzufügen bzw. Entfernen eines EventHandler-Delegaten wird während der Auslösung des Ereignisses ausgesetzt. Dies entspricht der Behandlung von MulticastDelegate-basierten Ereignissen in der Common Language Runtime (CLR). Beachten Sie außerdem, dass die Reihenfolge, in der die Rendering-Ereignisse aufgerufen werden, nicht festgelegt werden kann. Wenn Sie über mehrere EventHandler-Delegaten verfügen, die auf einer bestimmten Reihenfolge basieren, registrieren Sie ein einzelnes Rendering-Ereignis, und bündeln Sie die Delegaten selbst in der richtigen Reihenfolge.