Ich hatte den Eindruck, dass dispatcher
der Priorität .__ der Vorgänge in der Warteschlange folgen und die Vorgänge basierend auf der Priorität Oder der Reihenfolge ausführen wird, in der der Vorgang der Warteschlange hinzugefügt wurde (wenn dieselbe Priorität) bis mir gesagt wurde, dass dies bei WPF UI dispatcher
nicht der Fall ist.
Mir wurde gesagt, dass, wenn eine Operation im UI-Thread länger dauert, beispielsweise eine Datenbank gelesen wird. Der UI-Dispatcher versucht, die nächsten Operationen in der Warteschlange auszuführen. Ich konnte mich nicht damit abfinden Schreiben Sie eine WPF-Beispielanwendung, die eine Schaltfläche und drei Rechtecke enthält. Durch Klicken auf die Schaltfläche werden die Rechtecke mit verschiedenen Farben gefüllt.
<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>
und im 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");
}
}
Der kommentierte Code funktioniert erwartungsgemäß. Die Methoden werden auf der Grundlage von DispatcherPriority
aufgerufen. Außerdem wird die Bildschirmaktualisierung angezeigt, nachdem die einzelnen Operationen abgeschlossen wurdenOrder
ist One, Two, Three
. Farben werden nacheinander gezeichnet.
Nun wird der Arbeitscode, in dem DispatcherPriority
nicht erwähnt wird, erwähnt .__ (Ich gehe davon aus, dass er standardmäßig Normal
wäre). Die Reihenfolge ist immer noch One, Two, Three
, aber wenn ich ein MessageBox
in den Methoden zeige, wird
Thrid
popup wird zuerst angezeigt, dann Two
dann One
, aber wenn ich debugge, konnte ich die Methoden sehen
Wird in der erwarteten Reihenfolge aufgerufen (IntelliTrace zeigt sogar an, dass ein Meldungsfeld angezeigt wird, aber ich sehe es zu diesem Zeitpunkt nicht auf dem Bildschirm und erst nach Abschluss der letzten Operation.) Es ist nur so, dass die MessageBox
es auf der Rückseite angezeigt werden Auftrag.
Ist es, weil MessageBox.Show
ein blockierender Aufruf ist und der Vorgang gelöscht wird, nachdem die Nachricht geschlossen wurde.
Sogar dann sollte die Reihenfolge der MessageBox
auch One
, Two and
Drei` sein.
Bevor Sie sich mit dem Verhalten Ihres Codes beschäftigen, müssen Sie die Prioritäten von Dispatcher
verstehen. DispatcherPriority
ist in Bereiche unterteilt, wie im Bild unten gezeigt.
Wenn Sie einfach 4 Aktionen zu 4 oben in die Warteschlange stellen, wird Dispatcher
angezeigt. Die Foreground
-Warteschlange wird zuerst ausgeführt, dann die Background
und dann die letzte Idle
-Warteschlange. Priorität 0 wird nicht ausgeführt.
Nun dein Code:
Drei Tasks werden in der 1. Variable in background
, 2. in der background
und 3. in der foreground
-Warteschlange in die Warteschlange gestellt. Der dritte wird also zuerst ausgeführt. dann 2. Aufgabe, weil sie höhere Priorität hat als 1. Aufgabe. Ich hoffe das klärt es.
Einige weitere Beobachtungen helfen Ihnen dabei, es besser zu verstehen. Was ist, wenn Sie die Prioritäten auf 7,8 und 9 gesetzt haben. Da dies eine Vordergrundwarteschlange ist, wird 7 zuerst ausgeführt, dann 7 und dann 8. Einer nach dem anderen und ausschließlich In dieser Reihenfolge und während 7 ausgeführt wird, warten 8 und 9, was bedeutet, dass foreground
queue synchron zueinander ausgeführt wird.
Die Warteschlange Background
und Idle
verhält sich jedoch nicht so, wenn die Ausführung asynchron zu anderen Tasks ist und Tasks der Priorität folgen. Und zuerst Background
und die Idle
-Warteschlange.
Hoffe, diese Erklärung wird einigermaßen klarer.
Dies liegt daran, dass der erste MessageBox
den UI-Thread blockiert.
Was Dispatcher.BeginInvoke()
unter der Haube tut, nimmt Ihren Delegierten und plant, dass er im nächsten UI-Zeitraum auf dem Haupt-UI-Thread ausgeführt wird. MessageBox
blockiert jedoch den Thread, von dem aus er aufgerufen wird, bis er geschlossen wird. Das bedeutet, dass das zweite MessageBox
nicht angezeigt werden kann, bis das erste gelöscht wird, da der UI-Thread-Scheduler erkennt, dass der Thread bereits verwendet wird (und wartet, bis das erste MessageBox
gelöscht wird) und den nächsten Delegaten mit dem zweiten MessageBox
nicht ausführen kann.