簡體   English   中英

了解WPF Dispatcher.BeginInvoke

[英]Understanding the WPF Dispatcher.BeginInvoke

我的印象是dispatcher將遵循排隊的操作的優先級,並根據優先級或操作添加到隊列的順序(如果相同的優先級)執行操作,直到我被告知這不是WPF UI dispatcher

有人告訴我,如果UI線程上的操作持續時間較長,則表示數據庫讀取UI調度程序只是嘗試執行隊列中的下一組操作。 我無法接受它,因此決定編寫一個示例WPF應用程序,其中包含一個按鈕和三個矩形,點擊按鈕,矩形填充不同的顏色。

<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>

並在代碼隱藏

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");
    }
}

注釋代碼按預期工作,基於DispatcherPriority調用方法,並且我還可以在每個操作完成后看到屏幕刷新。 OrderOne, Two, Three 顏色是一個接一個地繪制的。

現在沒有提到DispatcherPriority的工作代碼(我假設它默認為Normal )順序仍然是One, Two, Three但是如果我在方法中顯示一個MessageBox
Thrid popup首先顯示然后是Two然后是One但是當我調試時我可以看到方法
在預期的順序調用(甚至智能跟蹤顯示一個消息框顯示,但我沒有看到它在屏幕上,當時看到它最后一次操作完成之后。)它只是在MessageBox ES在所示相反的順序。

是因為MessageBox.Show是一個阻塞調用,並且在消息關閉后清除了操作。
即便如此, MessageBox的順序也應該是OneTwo and Three`?

在介紹代碼行為之前,先了解Dispatcher的優先級。 DispatcherPriority分為范圍,如下圖所示。

的DispatcherPriority

如果您只是在Dispatcher上將4個操作排隊到4個以上范圍。 Foreground隊列首先執行,然后執行Background ,然后執行最后一個Idle隊列。 優先級0不會被執行。

現在你的代碼:

三個任務中排隊第一個background ,在第二background中,三foreground隊列。 所以第3次將首先被執行。 然后第二個任務導致它具有比第一個任務更高的優先級 我希望能夠清除它。

雖然更多的觀察將幫助您更好地理解它,如果您將優先級設置為7,8和9,那么如果這是一個前台隊列,則7將先執行然后執行7然后執行8.然后逐個執行按此順序,當7執行時,8和9將等待,這意味着foreground隊列將彼此同步執行。

但是BackgroundIdle隊列不會以這種方式運行,其中執行與其他任務異步,任務將遵循優先級。 第一個BackgroundIdle隊列。

希望這個解釋在某種程度上得到澄清。

這是因為第一個MessageBox阻止了UI線程

Dispatcher.BeginInvoke()正在做什么是接受你的委托並安排它在下一個空閑時段期間在主UI線程上運行。 但是, MessageBox將阻止它被調用的任何線程,直到它被關閉。 這意味着第二個MessageBox在第一個被清除之前無法顯示,因為UI線程調度程序發現該線程已被使用(等待第一個MessageBox被清除)並且無法執行包含第二個MessageBox的下一個委托。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM