Comprendre le Dispatcher WPF.BeginInvoke
J'étais sous l'impression que le dispatcher
suivra la priorité
des opérations en file d'attente et exécuter les opérations sur la base de la priorité
ou l'ordre dans lequel l'opération a été ajouté à la file d'attente(si même priorité)
jusqu'à ce qu'on m'a dit que ce n'est pas le cas dans le cas de la WPF UI dispatcher
.
M'a dit que si une opération sur le thread de l'INTERFACE utilisateur prend de plus longue durée-dire une base de données en lecture
l'INTERFACE utilisateur répartiteur simple tente d'exécuter la prochaine série d'opérations dans la file d'attente.
Je ne pouvais pas venir à termes avec elle donc décidé d'écrire un exemple d'application WPF qui contient un bouton et trois rectangles, cliquez sur le bouton, les rectangles sont remplis avec des couleurs différentes.
<StackPanel>
<Button x:Name="FillColors" Width="100" Height="100"
Content="Fill Colors" Click="OnFillColorsClick"/>
<TextBlock Width="100" Text="{Binding Order}"/>
<Rectangle x:Name="RectangleOne" Margin="5" Width="100" Height="100" Fill="{Binding BrushOne}" />
<Rectangle x:Name="RectangleTwo" Margin="5" Width="100" Height="100" Fill="{Binding BrushTwo}"/>
<Rectangle x:Name="RectangleThree" Margin="5" Width="100" Height="100" Fill="{Binding BrushThree}"/>
</StackPanel>
et dans le code-behind
private void OnFillColorsClick(object sender, RoutedEventArgs e)
{
var dispatcher = Application.Current.MainWindow.Dispatcher;
dispatcher.BeginInvoke(new Action(() =>
{
//dispatcher.BeginInvoke(new Action(SetBrushOneColor), (DispatcherPriority)4);
//dispatcher.BeginInvoke(new Action(SetBrushTwoColor), (DispatcherPriority)5);
//dispatcher.BeginInvoke(new Action(SetBrushThreeColor), (DispatcherPriority)6);
dispatcher.BeginInvoke(new Action(SetBrushOneColor));
dispatcher.BeginInvoke(new Action(SetBrushTwoColor));
dispatcher.BeginInvoke(new Action(SetBrushThreeColor));
}), (DispatcherPriority)10);
}
private void SetBrushOneColor()
{
Thread.Sleep(10 * 1000);
Order = "One";
//MessageBox.Show("One");
BrushOne = Brushes.Red;
}
private void SetBrushTwoColor()
{
Thread.Sleep(12 * 1000);
Order = "Two";
//MessageBox.Show("Two");
BrushTwo = Brushes.Green;
}
private void SetBrushThreeColor()
{
Thread.Sleep(15 * 1000);
Order = "Three";
//MessageBox.Show("Three");
BrushThree = Brushes.Blue;
}
public string Order
{
get { return _order; }
set
{
_order += string.Format("{0}, ", value);
RaisePropertyChanged("Order");
}
}
Le code commenté fonctionne comme prévu les méthodes sont appelées en fonction de la DispatcherPriority
et j'ai aussi la chance de voir de rafraîchissement de l'écran après chaque opération a été terminée.
Order
est One, Two, Three
. Les couleurs sont tirés l'un après l'autre.
Maintenant le code de travail où la DispatcherPriority
n'est pas mentionné
( Je suppose que c'est par défaut à Normal
) l'ordre est toujours One, Two, Three
mais si je montre un MessageBox
à l'intérieur de l'méthodes, l'
Thrid
popup est de montrer d'abord, puis Two
puis One
mais quand je debug j'ai pu voir les méthodes sont
invoquée dans l'ordre attendu (IntelliTrace montre même qu'une boîte de message est affiché mais je ne le vois pas sur l'écran à ce moment et seulement après la dernière opération est terminée.) c'est juste que le MessageBox
es sont affichés dans l'ordre inverse.
Est-ce parce que MessageBox.Show
est un appel bloquant et le fonctionnement sont effacées après le message a été fermé.
Même alors, l'ordre de la MessageBox
devrait également être One
Two and
Trois"?
source d'informationauteur Vignesh.N
Vous devez vous connecter pour publier un commentaire.
Avant de descendre à votre code de comportement il est une condition préalable pour comprendre les priorités de
Dispatcher
.DispatcherPriority
est divisé en plages, comme montré dans l'image ci-dessous.Si vous avez simplement la file d'attente de 4 actions à 4 ci-dessus des plages sur
Dispatcher
. leForeground
file d'attente seront exécutés en premier, puis leBackground
et puis, en dernierIdle
file d'attente. la priorité 0 ne sera exécutée.Maintenant votre code:
Trois tâches sont en attente 1er
background
2ebackground
et 3ème enforeground
file d'attente. Donc, la 3ème sera exécuté en premier. puis la 2ème tâche de cause il a une plus grande priorité, puis 1ère tâche. J'espère que l'annule.Bien que certains plus de l'observation vous aidera à mieux le comprendre comme si vous avez défini les priorités des 7, 8 et 9. Et donc comme c'est un de premier plan de la file d'attente, 7 seront exécutés en premier, puis 7 puis 8. Un par un, et exclusivement, dans l'ordre, et alors que 7 est arriver exécuté, 8 et 9 s'attendre, sens
foreground
file d'attente sera exécuté de manière synchrone à chaque autre.Mais
Background
etIdle
file d'attente va pas se comporter de la sorte, la où l'exécution est asynchrone à d'autres tâches et les tâches de suivre la priorité. Et d'abordBackground
et laIdle
file d'attente.Espérons que cette explication précise, dans une certaine mesure.
C'est parce que la première
MessageBox
est le blocage de la thread d'INTERFACE utilisateur.Ce
Dispatcher.BeginInvoke()
est en train de faire sous le capot est de prendre votre délégué et de la programmation pour qu'il soit exécuté sur-le-main thread d'INTERFACE utilisateur au cours de la prochaine période d'inactivité. Cependant,MessageBox
bloquera selon le fil, elle est appelée à partir de jusqu'à ce qu'il est fermé. Cela signifie que le deuxièmeMessageBox
ne peut pas être affichée jusqu'à ce que le premier est effacé parce que le thread d'INTERFACE utilisateur planificateur voit que le thread est déjà en cours d'utilisation (en attente de la premièreMessageBox
être effacé) et ne peut pas exécuter la prochaine délégué contenant la deuxièmeMessageBox
.