【问题标题】:Loading GIF freezing sometimes有时加载 GIF 冻结
【发布时间】:2010-10-09 20:32:49
【问题描述】:

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

加载覆盖在多种不同的表单加载时工作正常,但在 30 秒上传过程中被召唤以确保耐心时无法正常工作(将 Word 文档打印为 PDF,然后将该 PDF 上传到 SQL Server)。此上传从表单中收集一些数据,将其放入对象中,然后完全在后台线程上运行。加载覆盖将出现,显示加载 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

【问题讨论】:

    标签: .net vb.net gdi+ gif


    【解决方案1】:

    “一些 COM”是相关的。你会遇到 COM 的公寓线程规则。必须在 STA 线程上创建像 Word 这样的 COM 对象。您的主 UI 线程符合条件,它从 Main() 开始,并且具有 [STAThread] 属性。您在另一个线程上进行的任何方法调用都会由 COM 自动封送到 STA 线程。给你的动画加糖。

    这不容易解决。您还需要一个必须是 STA 线程的后台线程,请使用 Thread.SetApartmentState()。并泵出一个消息循环,使用 Application.Run()。启动代码并退出循环很麻烦,请尝试使用覆盖 SetVisibleCore() 的表单,以免使其可见。

    【讨论】:

    • 这听起来很棒。澄清一下:我应该尝试将所有后台工作(COM)放入某种虚拟表单中,该表单是通过从 bg STA 线程调用 Application.Run(dummyForm) 开始的。感谢您的帮助!
    【解决方案2】:

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

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2011-08-21
      • 1970-01-01
      • 1970-01-01
      • 2015-03-10
      • 1970-01-01
      • 2013-06-24
      • 2022-06-12
      • 1970-01-01
      相关资源
      最近更新 更多