有时加载GIF冻结

时间:2009-02-25 16:07:32

标签: .net vb.net gdi+ gif

我正在尝试在Windows窗体顶部使用加载叠加层,在窗体顶部添加50%不透明图层并加载GIF,同时它在后台线程中执行它需要做的事情。叠加层是我在onPaint事件中绘制的窗体。

加载叠加层在多个不同的表单加载时工作正常,但在召唤时无法正常工作以确保在30秒上载过程中耐心(将Word文档打印到PDF,然后将该PDF上载到SQL Server)。此上载从表单收集一些数据,将其放入Object,然后完全在后台线程上运行。加载覆盖图将出现,显示第一帧加载GIF,然后只是冻结。 onPaint被触发并且图像框架正在更新,但它不可见

构造函数将表单设置为UserPainted:

Sub New()
    InitializeComponent()
    SetStyle(ControlStyles.UserPaint Or ControlStyles.Opaque, True) 
End Sub

然后,在Form.Shown事件中调用ImageAnimator.Animate方法:

Private Sub LoadingOverlay_Shown(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Shown
    If Not currentlyAnimating Then
        ImageAnimator.Animate(animatedImage, AddressOf Me.OnFrameChanged)
        currentlyAnimating = True
    End If
End Sub

onFrameChanged事件处理程序只是使表单无效:

Private Sub OnFrameChanged(ByVal sender As Object, ByVal e As System.EventArgs)
    'Force a call to onPaint
    Me.Invalidate()
End Sub

然后重写onPaint并完成绘图:

Protected Overrides Sub OnPaint(ByVal e As PaintEventArgs)
    MyBase.OnPaint(e)

    'Get the next frame ready for rendering
    ImageAnimator.UpdateFrames()

    'Draw the next frame in the animation.
    e.Graphics.DrawImage(Me.animatedImage, GetCenter(Me.animatedImage.Size))
    TextRenderer.DrawText(e.Graphics, strStatus, Me.Font, GetTextLocation(Me.animatedImage.Size), Color.White, Color.Black)

End Sub

最后,在Form Closing事件中调用ImageAnimator.StopAnimate方法:

Private Sub LoadingOverlay_FormClosed(ByVal sender As Object, ByVal e As System.Windows.Forms.FormClosedEventArgs) Handles Me.FormClosed
    If currentlyAnimating Then
        ImageAnimator.StopAnimate(animatedImage, AddressOf Me.OnFrameChanged)
        currentlyAnimating = False
    End If
End Sub

以下是如何调用和关闭加载叠加层:

Private Sub ShowLoadingOverlay()
    If Not blnLoadingOverlayVisible Then

        Me.Enabled = False

        patience = New LoadingOverlay()
        patience.Location = Point.Add(parent.PointToScreen(Me.Location), New Size(0, parent.ToolStrip.Height + parent.MenuStrip.Height))
        patience.Size = Me.Size
        patience.Show()
        patience.BringToFront()

        blnLoadingOverlayVisible = True

    End If
End Sub

Private Sub HideLoadingOverlay()
    If blnLoadingOverlayVisible Then
        'Close loading overlay'
        patience.Close()
        patience.Dispose()
        patience = Nothing
        Me.Enabled = True
        blnLoadingOverlayVisible = False
    End If
End Sub

2 个答案:

答案 0 :(得分:1)

“某些COM”是相关的。你会点击COM的公寓线程规则。必须在STA线程上创建类似Word的COM对象。您的主UI线程符合条件,它从Main()开始,并具有[STAThread]属性。您在另一个线程上调用的任何方法都会被COM自动封送到STA线程。搞砸你的动画。

这不容易修复。你需要一个必须是STA线程的后台线程,使用Thread.SetApartmentState()。并且泵出一个消息循环,使用Application.Run()。启动代码并退出循环是很尴尬的,尝试使用覆盖SetVisibleCore()的表单,这样就可以避免使其可见。

答案 1 :(得分:0)

最初一切都发生在一个后台线程中。总共运行3种方法。当我将上传线程(大约工作量的1/2)移动到另一个后台线程时,一切都“正常”(不完美,GIF在开始时仍会跳跃一点)。

移入第二个后台线程的上传方法根本不与GUI线程交互,它只是做一些COM(单词)和SQL的东西。长话短说,它有效,但我仍然不知道为什么。任何见解将不胜感激!