Condividi tramite


Procedura: Eseguire il rendering per ciascun intervallo di fotogramma usando CompositionTarget

Il motore di animazione WPF offre molte funzionalità per la creazione di animazioni basate su fotogrammi. Esistono tuttavia scenari applicativi in cui è necessario un controllo più dettagliato sul rendering per ogni fotogramma. L'oggetto CompositionTarget consente di creare animazioni personalizzate basate su un callback per fotogramma.

CompositionTarget è una classe statica che rappresenta la superficie di visualizzazione in cui viene disegnata l'applicazione. L'evento Rendering viene attivato ogni volta che la scena dell'applicazione viene disegnata. La frequenza dei fotogrammi di rendering è il numero di volte in cui viene disegnata la scena al secondo.

Annotazioni

Per un esempio di codice completo con CompositionTarget, vedere Using the CompositionTarget Sample.

Esempio

L'evento Rendering viene generato durante il processo di rendering di WPF. Nell'esempio seguente viene illustrato come registrare un delegato EventHandler al metodo statico Rendering su CompositionTarget.

// Add an event handler to update canvas background color just before it is rendered.
CompositionTarget.Rendering += UpdateColor;
' Add an event handler to update canvas background color just before it is rendered.
AddHandler CompositionTarget.Rendering, AddressOf UpdateColor

È possibile utilizzare il metodo del gestore eventi di rendering per creare contenuto di disegno personalizzato. Questo metodo del gestore eventi viene chiamato una volta per fotogramma. Ogni volta che WPF trasmette i dati di rendering persistenti nella struttura ad albero visuale verso il grafico di scena della composizione, viene chiamato il metodo del gestore eventi. Inoltre, se le modifiche alla struttura visuale ad albero richiedono aggiornamenti al grafico della scena compositiva, viene chiamato anche il metodo del gestore eventi. Si noti che il metodo del gestore eventi viene chiamato dopo il calcolo del layout. Tuttavia, è possibile modificare il layout nel metodo del gestore eventi, il che significa che il layout verrà calcolato ancora una volta prima del rendering.

Nell'esempio seguente viene illustrato come specificare un disegno personalizzato in un metodo del gestore eventi CompositionTarget. In questo caso, il colore di sfondo del Canvas viene disegnato con un valore cromatico basato sulla posizione del cursore del mouse. Se si sposta il mouse all'interno del Canvas, il colore di sfondo cambia. Viene inoltre calcolata la frequenza media dei fotogrammi, in base al tempo trascorso e al numero totale di fotogrammi renderizzati.

// 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));
}
' 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

È possibile scoprire che il disegno personalizzato viene eseguito a velocità diverse su computer diversi. Ciò è dovuto al fatto che il disegno personalizzato non è indipendente dalla frequenza dei fotogrammi. A seconda del sistema in esecuzione e del carico di lavoro del sistema, l'evento Rendering può essere chiamato un numero diverso di volte al secondo. Per informazioni sulla determinazione delle capacità e delle prestazioni dell'hardware grafico per un dispositivo che esegue un'applicazione WPF, vedere livelli di rendering grafico.

L'aggiunta o la rimozione di un delegato di rendering EventHandler mentre l'evento è in esecuzione verrà ritardata fino al termine dell'esecuzione dell'evento. Questo è coerente con il modo in cui gli eventi basati su MulticastDelegatevengono gestiti in Common Language Runtime (CLR). Si noti anche che non è garantito che gli eventi di rendering vengano chiamati in un ordine specifico. Se hai più delegati EventHandler che si basano su un ordine specifico, dovresti registrare un singolo evento Rendering e multiplexare i delegati nell'ordine corretto.

Vedere anche