1

バックグラウンドスレッドで必要なことを実行しながら、読み込みGIFを含むWindowsフォームの上に50%不透明レイヤーを追加するWindowsフォームの上に読み込みオーバーレイを使用しようとしています。オーバーレイは、onPaint イベントで描画している Windows フォームです。

ローディング オーバーレイは、複数の異なるフォーム ロードで正常に動作しますが、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

最後に、ImageAnimator.StopAnimate メソッドが Form Closing イベントで呼び出されます。

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 のアパートメント スレッド ルールに当てはまります。Word などの COM オブジェクトは、STA スレッドで作成する必要があります。メイン UI スレッドが修飾され、Main() で始まり、[STAThread] 属性があります。別のスレッドで行うメソッド呼び出しは、COM によって自動的に STA スレッドにマーシャリングされます。アニメーションをグミングアップします。

これを修正するのは簡単ではありません。STA スレッドである必要があるバックグラウンド スレッドも必要です。Thread.SetApartmentState() を使用してください。メッセージ ループをポンピングするには、Application.Run() を使用します。コードを開始してループを終了するのは厄介です。 SetVisibleCore() をオーバーライドするフォームを使用してみてください。

于 2009-02-25T19:15:20.190 に答える
0

最初は、すべてが単一のバックグラウンドスレッドで発生しています。実行されるメソッドは全部で3つあります。アップロードスレッド(作業の約1/2を実行します)を別のバックグラウンドスレッドに移動すると、すべてが「OK」になります(完全ではなく、GIFは最初は少しジャンプします)。

2番目のバックグラウンドスレッドに移動されたアップロードメソッドは、GUIスレッドとはまったく対話せず、COM(ワード)とSQLの処理を実行するだけです。簡単に言えば、それは機能していますが、私はまだ理由がわかりません。どんな洞察も大歓迎です!

于 2009-02-25T16:41:54.913 に答える