方法: CompositionTarget を使用したフレームの間隔ごとの描画

WPF のアニメーション エンジンには、フレームベースのアニメーションを作成するためのさまざまな機能が用意されています。 ただし、フレームベースの描画をさらにきめ細かく制御することが必要となるアプリケーション シナリオがあります。 CompositionTarget オブジェクトを使用すると、フレームごとのコールバックに基づいて、カスタム アニメーションを作成できます。

CompositionTarget は、アプリケーションが描画される表示サーフェイスを表す静的クラスです。 アプリケーションのシーンが描画されるたびに Rendering イベントが発生します。 レンダリング フレーム レートは、1 秒あたりのシーンの描画回数です。

注意

CompositionTarget を使用したコード サンプル全体については、CompositionTarget サンプルの使用に関する記事を参照してください。

Rendering イベントは、WPF のレンダリング プロセス中に発生します。 次の例では、CompositionTarget の静的な Rendering メソッドに EventHandler デリゲートを登録する方法を示しています。

// 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

独自の描画イベント ハンドラー メソッドを使用して、描画のカスタム コンテンツを作成できます。 このイベント ハンドラー メソッドは、フレームごとに 1 回呼び出されます。 WPF がビジュアル ツリーの永続化されたレンダリング データを合成シーン グラフにマーシャリングするたびに、イベント ハンドラー メソッドが呼び出されます。 さらに、ビジュアル ツリーに対する変更によって合成シーン グラフが強制的に更新される場合も、イベント ハンドラー メソッドが呼び出されます。 イベント ハンドラー メソッドは、レイアウトが計算された後に呼び出されます。 ただし、イベント ハンドラー メソッド内でレイアウトを変更できます。つまり、そのレイアウトは、描画する前にもう一度計算されることになります。

次の例は、CompositionTarget イベント ハンドラー メソッドでカスタム描画を指定する方法を示します。 この場合、Canvas の背景色は、マウスの座標位置に基づくカラー値で描画されます。 Canvas 内でマウスを移動すると、その背景色が変わります。 また、現在の経過時間および描画されたフレームの合計数に基づいて、平均フレーム レートが計算されます。

// 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

カスタム描画は、コンピューターごとに異なる速度で実行される場合があります。 これは、カスタム描画がフレーム レートに依存するためです。 実行しているシステムとそのシステムの負荷に応じて、Rendering イベントが 1 秒あたりに呼び出される回数が異なる場合があります。 WPF アプリケーションを実行するデバイスのグラフィックス ハードウェアの機能およびパフォーマンスの決定については、「グラフィックスの描画層」を参照してください。

イベントの発生中の描画 EventHandler デリゲートの追加または削除は、イベントが終了するまで遅延します。 これは、MulticastDelegate ベースのイベントが共通言語ランタイム (CLR) で処理される方法と一貫しています。 また、描画イベントが特定の順序で呼び出されるかどうかは保証されません。 特定の順序に依存する複数の EventHandler デリゲートがある場合、単一の Rendering イベントを登録し、手動でデリゲートを正しい順序で多重化する必要があります。

関連項目