web-dev-qa-db-de.com

Informationen zum WPF-Dispatcher.BeginInvoke

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 MessageBoxes 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 andDrei` sein.

15
Vignesh.N

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.

 DispatcherPriority

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.

3
Kylo Ren

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.

1
Adam Wilson