WPF 动画引擎为创建基于帧的动画提供了许多功能。 但是,在有些应用程序方案中,您需要基于每个帧来以更细的粒度控制呈现。 使用 CompositionTarget 对象,可以基于每个帧回调来创建自定义动画。
CompositionTarget 是一个静态类,表示您的应用程序要在其上进行绘制的显示图面。 每次绘制应用程序的场景时,都会引发 Rendering 事件。 呈现帧速率是指每秒绘制场景的次数。
![]() |
---|
有关使用 CompositionTarget 的完整代码示例,请参见 Using the CompositionTarget Sample(使用 CompositionTarget 示例)。 |
示例
在 WPF 呈现过程中,会激发 Rendering 事件。 下面的示例演示如何向 CompositionTarget 上的静态 Rendering 方法中注册 EventHandler 委托。
' 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;
您可以使用自己的呈现事件处理程序方法创建自定义绘图内容。 对每帧调用一次此事件处理程序方法。 每次 WPF 将可视化树中的持久呈现数据封送到组合场景关系图中时,都会调用您的事件处理程序方法。 另外,如果更改可视化树将强制更新组合场景关系图,也会调用您的事件处理程序方法。 请注意,计算布局后会调用您的事件处理程序方法。 但是,您可以修改您的事件处理程序方法中的布局,这意味着在呈现之前将再计算一次布局。
下面的示例演示如何在 CompositionTarget 事件处理程序方法中提供自定义绘图。 在本例中,Canvas 的背景色是基于鼠标的坐标位置,用颜色值绘制的。 如果您将鼠标放在 Canvas 内部,则它的背景色将发生变化。 另外,将基于当前的运行时间和所呈现帧的总数来计算平均帧速率。
' 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));
}
您可能会发现自定义绘图在不同计算机上以不同的速度运行, 这是由于自定义绘图与帧速率有关。 根据所运行的系统以及系统的工作负荷,每秒调用 Rendering 事件的次数可能会有所不同。 有关为运行 WPF 应用程序的设备确定图形硬件功能和性能的信息,请参见图形呈现层。
在激发事件时对呈现 EventHandler 委托的添加或移除将延迟到事件完成激发之后。 这与基于 MulticastDelegate 的事件在公共语言运行时 (CLR) 中的处理方式一致。 另请注意,无法保证按照任何特定顺序来调用呈现事件。 如果您有多个 EventHandler 委托依赖特定的顺序,则应当注册一个 Rendering 事件,并按照正确的顺序自己多路复用这些委托。