1

我正在尝试在 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
4

2 回答 2

1

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

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

于 2009-02-25T19:15:20.190 回答
0

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

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

于 2009-02-25T16:41:54.913 回答