Troublé par le comportement de Répartiteur.BeginInvoke()
Quelqu'un pourrait jeter de la lumière sur un problème que je vais avoir?
Je suis en train de travailler sur un projet wpf. Le scénario est comme ci-dessous:
J'ai besoin pour faire apparaître une fenêtre(la fenêtre modèle) sur la thread de l'INTERFACE utilisateur, puis le fermer. Ces travaux sont démarrés à partir d'un autre thread d'INTERFACE utilisateur (pour dissuader les utilisateurs de cliquer sur l'INTERFACE principale de la fenêtre.) puis-je fermer cette fenêtre. Le code principal sont affichés ci-dessous. Et il fonctionne.
Autant que je sache, la méthode close serait pas exécutée avant ShowDialog()
retourne (au moins c'est le cas sur le thread de l'INTERFACE utilisateur, je veux dire le code sans répartiteur), quelqu'un a une expérience avec multithread?
Window window;
private void Button_Click(object sender, RoutedEventArgs e)
{
Thread thread = new Thread(() =>
{
//create a window and let user work from this thread
//code is omitted.
//create another window on main UI thread
Application.Current.Dispatcher.BeginInvoke(new Action(() =>
{
window = new Window();
window.ShowDialog();
}));
//do some work here
Thread.Sleep(1000);
Application.Current.Dispatcher.BeginInvoke(new Action(() =>
{
//Thread.Sleep(1000);
window.Close();
}));
});
thread.Start();
}
Merci pour votre temps!
OriginalL'auteur xiaoheixiaojie | 2011-05-03
Vous devez vous connecter pour publier un commentaire.
Donc, si je comprends votre question correctement, vous voulez dire que ce code fonctionne exactement de la manière que vous voulez, mais vous êtes juste essayer de comprendre comment (et pourquoi), il fonctionne?
Voici comment cela fonctionne. Tout d'abord, votre thread exécute ce code:
Que les files d'attente de votre action sur le principal (UI) du thread répartiteur de la file d'attente, puis retourne immédiatement: votre thread de travail continue de courir.
Lors de l'Application au premier lancement (généralement via le code généré par le compilateur qui initialise votre Application.xaml objet, mais vous pouvez également le faire explicitement par l'Application appelante.Exécuter), il a commencé sa boucle de message, ce qui va quelque chose comme ceci (pseudocode, très très simplifié):
Donc à un certain point, peu de temps après la file d'attente de l'action, le thread de l'INTERFACE utilisateur va se déplacer à tirer de votre action de la file d'attente et en l'exécutant, à quel point votre action crée une fenêtre et l'affiche sous forme modale.
La fenêtre modale commence maintenant sa propre boucle de message, ce qui va quelque chose comme ceci (encore une fois, très simplifié):
Plus tard, votre thread exécute ce code:
Encore une fois, votre action est mis en file d'attente pour le thread de l'INTERFACE utilisateur du répartiteur de la file d'attente, puis le BeginInvoke appel renvoie immédiatement et votre thread de travail continue de courir.
Donc, tôt ou tard, le thread de l'INTERFACE utilisateur de la boucle de message va se déplacer à la file d'attente et l'exécution de votre action, qui raconte la fenêtre pour la fermer. Cela a essentiellement le même effet que l'utilisateur en cliquant sur la barre de titre du bouton "X", ce qui est parfaitement normal de le faire même lorsque vous êtes à l'intérieur d'une boîte de dialogue modale. Cela provoque ShowDialog de la boucle de message à la fin (parce que la fenêtre est maintenant fermé), à quel point le dialogue est caché et l'autre windows sont réactivées, ShowDialog retourne, votre origine (ShowDialog) l'action est terminée et donc des retours, et le contrôle revient à l'original de la boucle de message dans l'Application.Exécutez.
Noter qu'il y a une file d'attente dispatcher par fil, pas un par boucle de message. Donc votre "proche" de la action va dans la même file d'attente que votre "afficher la boîte de dialogue" action fait. C'est un autre morceau de code à faire le message en boucle d'interrogation maintenant (une à l'intérieur de ShowDialog au lieu de l'un à l'intérieur de l'Application.Exécuter), mais les principes de base de la boucle sont les mêmes.
OriginalL'auteur Joe White
BeginInvoke
est une méthode non bloquante; il s'y ajoute l'action pour le répartiteur de la file d'attente, et ne pas attendre pour sa réalisation. Vous devez utiliserInvoke
au lieu de cela, ce qui appelle la méthode de façon synchrone sur le répartiteur fil.OriginalL'auteur Thomas Levesque