如何:使用 CompositionTarget 以每帧间隔呈现

WPF 动画引擎提供了许多用于创建基于帧的动画的功能。 但是,在某些情况下,需要对每个帧的呈现进行精细控制。 CompositionTarget 对象提供基于每帧回调创建自定义动画的功能。

CompositionTarget 是一个静态类,表示用于绘制应用程序的显示表面。 每次绘制应用程序场景时,Rendering 事件都会被触发。 呈现帧速率是每秒绘制场景的次数。

注释

有关使用 CompositionTarget 的完整代码示例,请参阅使用 CompositionTarget 示例

示例:

Rendering 事件在 WPF 呈现过程中引发。 以下示例演示如何将 EventHandler 委托注册到 Rendering 上的静态 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

可以使用呈现事件处理程序方法创建自定义绘图内容。 每个帧调用一次此事件处理程序方法。 每次 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 事件可以调用每秒不同的次数。 有关确定运行 WPF 应用程序的设备的图形硬件功能和性能的信息,请参阅 图形呈现层

在引发事件时对呈现 EventHandler 委托的添加或移除会延迟到事件完成引发之后。 这与在公共语言运行时(CLR)中处理基于 MulticastDelegate的事件的方式一致。 另请注意,渲染事件不保证按照任何特定顺序被调用。 如果有多个 EventHandler 委托依赖特定的顺序,则应当注册一个 Rendering 事件,然后自行按照正确的顺序多路复用这些委托。

另请参阅