2009-02-25 10 views
1

J'essaie d'utiliser une surcouche de chargement au-dessus d'un formulaire Windows qui ajoute une couche opaque de 50% au-dessus d'un formulaire Windows avec un chargement GIF, alors qu'il fait ce qu'il doit faire dans un fil d'arrière-plan. La superposition est une forme de fenêtre que je dessine dans l'événement onPaint. Le chargement de superposition fonctionne correctement sur plusieurs charges de formulaire différentes, mais ne fonctionne pas correctement lorsqu'il est invoqué pour assurer la patience pendant un processus de téléchargement de 30 secondes (qui imprime un document Word en PDF, puis télécharge ce PDF sur un SQL Server). Ce téléchargement collecte certaines données du formulaire, les place dans un objet, puis fonctionne entièrement sur un thread d'arrière-plan. La superposition de chargement apparaîtra, montrera la première image chargeant le GIF, puis gèlera juste. Le OnPaint est tiré et se le cadre de l'image est mise à jour, mais il n'est pas visibleChargement du gel GIF parfois

constructeur définit la forme à UserPainted:

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

Ensuite, en cas Form.Shown la ImageAnimator.Animate méthode est appelée:

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 

le gestionnaire d'événements onFrameChanged Invalide juste la forme:

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

Alors OnPaint est surchargée et réalise le dessin:

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 

Enfin, la méthode ImageAnimator.StopAnimate est appelée dans l'événement de clôture du formulaire:

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 

Voici comment la superposition de chargement est appelé et fermé :

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 

Répondre

1

"certains COM" est pertinent. Vous allez frapper l'appartement de COM enfilant rulez. Un objet COM comme Word doit être créé sur un thread STA. Votre thread d'interface utilisateur principal est qualifié, il commence à Main() et il a l'attribut [STAThread]. Tous les appels de méthode que vous effectuez sur un autre thread sont automatiquement marshalés par COM dans le thread STA. Gumming votre animation.

Ce n'est pas facile à réparer. Vous auriez besoin d'un thread d'arrière-plan qui doit également être un thread STA, utilisez Thread.SetApartmentState(). Et pomper une boucle de message, utilisez Application.Run(). Pour démarrer votre code et quitter la boucle, essayez d'utiliser un formulaire qui remplace SetVisibleCore() pour éviter de le rendre visible.

+0

Cela semble génial. Juste pour clarifier: je devrais essayer de mettre tout le travail d'arrière-plan (COM) en quelque sorte d'une forme factice qui a commencé en appelant Application.Run (dummyForm) d'un fil de STG de bg. Merci pour l'aide! – Joey

0

Initialement, tout se passe dans un thread d'arrière-plan unique. Il y a 3 méthodes totales qui fonctionnent. Quand j'ai déplacé le fil de téléchargement (qui fait environ la moitié du travail) dans un autre fil de fond, tout est "ok" (pas parfait, GIF saute encore un peu au début).

La méthode de téléchargement qui a été déplacée dans un deuxième thread d'arrière-plan n'interagit pas du tout avec le thread graphique, elle ne fait que du COM (mot) et du SQL. Longue histoire courte, ça marche, mais je ne sais toujours pas pourquoi. Toute idée serait grandement apprécié!

Questions connexes