2

我在按钮上放置了一个动画 gif。它的动画效果很好(大多数时候:P),但是当窗口被重绘(重绘)时,动画停止了。我在处理 Paint 事件时尝试刷新按钮 (button.Refresh() ),但它没有解决问题。\

任何人都知道如何解决这个问题?

4

1 回答 1

3

也许我错了,但我认为问题在于它不是在重绘表单时停止动画,而是当动画对象被另一个窗口遮挡时。这是预期的行为;错误在于,在 Windows Vista 和 Windows 7 中,显示是合成的,因此即使窗口被“遮挡”,它也从未真正被遮挡,并且在未遮挡时它永远不会收到绘制消息,这将重新启动动画。

此错误似乎会影响任何带有动画对象的 ButtonBase 派生控件。

问题在于 Control.IsWindowObcured 函数。它将返回 true。您可以在 ButtonBase.cs 文件的 System.Windows.Forms.ButtonBase.OnFrameChanged 中看到,最后有一行代码显示:

if (IsWindowObscured) {
 StopAnimate();
 return;
}

这就是问题所在。

仅供参考,从 ImageAnimator 线程调用 OnFrameChanged。这是在 ImageAnimator.Animate(image, eventhandler) 中指定的回调。ButtonBase 在私有 void Animate(bool animate) 函数中设置它。ImageAnimator 线程每 50 毫秒轮询一次,并检查是否需要为它正在监视的任何图像添加新帧;如果是这样,它会设置一个标志以使控件无效并绘制新框架。

由于这是我们无法访问的,我认为我们对此无能为力。作为一种解决方法,我在我的表单中实现了一个计时器,该计时器每 500 毫秒使控件无效,因此如果之前已停止,它将强制它重新启动。我们无法覆盖甚至访问它,这很烦人。恐怕唯一的解决方案是上面的hack,或者创建或使用您自己或第三方创建的控件。

澄清一下——这只是使用桌面组合的 Windows Vista 或 Windows 7 上的问题。问题是窗口永远不会真正被遮挡,就像不使用桌面组合时一样。它们总是由窗口管理器缓冲。(Windows 2000+ 中有特殊的分层窗口,但暂时忽略它)。以前,如果窗口的某些部分不在屏幕上或被另一个窗口遮挡,则它们不可用。当它们重新出现时,通过改变焦点或位置等,系统将通知该区域重新绘制自己。但是,当使用桌面合成时,从不需要重新绘制,因为窗口的实际内容在其他地方缓冲。这就是为什么窗口预览在任务栏中工作的原因,例如 Flip-3d。副作用是,希望在被遮挡后再次可见时获得绘制消息的代码将失败。ButtonBase 代码希望在返回视图后收到一条绘制消息,这将再次启动动画。因此,这种优化成为了一个错误。

该问题应在 Microsoft Connect 中报告,但不太可能得到解决。

于 2009-09-02T13:15:20.197 回答