Création d'une fenêtre WPF à partir d'un WinForms BackgroundWorker
-
06-07-2019 - |
Question
J'ai une dll WPF qui contient un certain nombre de classes Window et expose les méthodes qui affichent ces fenêtres.
J'ai également un projet WinForms distinct qui appelle l'une de ces méthodes dans le projet WPF dans la méthode DoWork d'un composant BackgroundWorker.
Sur la ligne de code qui instancie une fenêtre WPF, j'obtiens l'erreur d'exécution suivante:
Le thread appelant doit être STA, car de nombreux composants d'interface utilisateur en ont besoin.
Une recherche google m'a permis de cette discussion . (Il s'avère que Jon Skeet répond aux questions sur d'autres sites en plus de Stack Overflow!). Il a créé un lien vers cet article , qui indique
Le composant BackgroundWorker fonctionne bien avec WPF ...
Cet article mentionne également l'utilisation de la classe DispatcherObject, mais je ne comprends pas comment le faire fonctionner et je préfère simplement continuer à utiliser mon composant BackgroundWorker.
Comme test, j’ai créé le code suivant pour reproduire l’erreur. Dans la bibliothèque de classes WPF, voici le code dans Window1.xaml.vb
Partial Public Class Window1
Public Shared Function ShowMe() As Boolean?
Dim w = New Window1 'Error appears on this line.
Return w.ShowDialog()
End Function
End Class
Dans l'application WinForms, voici le code dans Form1.vb
Imports System.ComponentModel
Public Class Form1
Private WithEvents worker As BackgroundWorker
Private Sub doWord(ByVal sender As Object, ByVal e As DoWorkEventArgs) Handles worker.DoWork
WpfLibrary.Window1.ShowMe()
End Sub
Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
worker = New BackgroundWorker
worker.RunWorkerAsync()
End Sub
End Class
Même si le composant BackgroundWorker est placé dans Window1.xaml.vb, la même erreur se produit. Cet article est donc faux et je ne peux pas vraiment utiliser BackgroundWorker avec WPF? Ou dois-je faire autre chose pour que cela fonctionne?
Si BackgroundWorker ne fonctionne pas, comment puis-je remplacer le code dans Form1.vb ci-dessus pour utiliser un répartiteur à la place?
La solution
Vous pouvez utiliser un travailleur d'arrière-plan avec WPF, ce n'est pas votre problème.
Votre problème est que vous ne pouvez effectuer aucune tâche mettant à jour l'interface utilisateur en dehors du thread principal de l'interface utilisateur dans une application winform ou WPF et que la méthode DoWork de BackgroundWorker s'exécute dans un autre thread.
Par conséquent, vous devez ouvrir la nouvelle fenêtre en dehors du fil d’arrière-plan de BackgroundWorker, avant de démarrer BackgroundWorker ou dans son événement RunWorkerCompleted.
Sans connaître le code qui entoure l'appel pour ouvrir la fenêtre, il m'est difficile de vous conseiller, mais j'espère que cela vous orientera dans la bonne direction.
Autres conseils
Votre agent peut également créer son propre thread, le marquer comme STA, puis appeler Thread.Join ()
pour attendre la fin de celui-ci. Vous pourrez alors créer et afficher la fenêtre sur votre nouveau thread (notez cependant qu'aucun autre thread ne pourra interagir avec celle-ci sans utiliser le répartiteur).
Exemple en C #:
Thread workerThread = new Thread(ShowMyWindow);
workerThread.SetApartmentState(ApartmentState.STA);
workerThread.Start();
workerThread.Join();
Et ensuite:
private void ShowMyWindow()
{
WpfLibrary.Window1.ShowMe()
}