2014-09-22 71 views
15

我的印象是,dispatcher將按照優先級的業務 排隊,並執行基於優先級 或在其中操作被添加到隊列的順序操作(如果同樣的優先權) ,直到我被告知這不是WPF UI dispatcher的情況。瞭解WPF Dispatcher.BeginInvoke

有人告訴我,如果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彈出窗口顯示第一則Two然後One但是當我調試時,我可以看到按預期順序調用的方法是
(IntelliTrace甚至顯示消息框顯示,但當時我沒有在屏幕上看到它,只有在最後一個操作完成後才能看到它。 )它只是MessageBox es以相反的順序顯示。

是因爲MessageBox.Show是一個阻塞調用和消息已被關閉後的操作將被清除。
即使這樣,MessageBox的訂單也應該是One,Two and三`?

+0

這簡直是在您關閉該消息框的順序的影響。由於最後一個位於頂部,這是您關閉的第一個。與DispatcherPriority沒有任何關係。 – 2014-09-22 17:35:21

+0

是的,我認爲是這樣,但在關閉最上面的那個之前我無法看到其他的MessageBox。 – 2014-09-23 04:42:47

+0

@ Vignesh.N我的答案解釋了您的查詢嗎? – 2016-09-27 05:34:49

回答

1

這是因爲第一個MessageBox阻塞了UI線程

什麼Dispatcher.BeginInvoke()是引擎蓋下做的是把你的委託,並安排其到主UI線程在它的下一個空閒時間運行。但是,MessageBox將阻止它被調用的任何線程,直到它關閉。這意味着第二個MessageBox不能顯示,直到第一個被清除,因爲UI線程調度程序發現線程已在使用中(等待第一個MessageBox被清除),並且無法執行包含第二個MessageBox的下一個代理。

+0

如果你是對的,我會希望消息框按照它們被調用的順序。因此1,2,3不是3,2 1 ... – blueprint 2015-09-10 12:49:55

+0

事實上,然而這裏的執行順序問題最可能被追蹤到嵌套BeginInvokes。外部BeginInvoke已經確保代碼在UI上運行。只需刪除內部的BeginInvokes就足以確保代碼按順序執行。由於您已經在UI線程中,因此從UI線程調用BeginInvoke可能會很容易出現意外的行爲。 – 2015-09-10 17:11:12

+0

你是完全正確的,我自己嘗試過。我也試過幾次,真正理解什麼是在這種情況下會在幕後,但不過我嘗試看看它,我來到了相同的結論:它應該是1,2,3,你能更詳細地解釋你在這裏的內部工作模式是什麼?究竟會發生什麼? – blueprint 2015-09-14 16:31:20

4

之前灌進你的代碼的行爲是理解的Dispatcher優先級的先決條件。 DispatcherPriority分爲如下圖所示的範圍。

DispatcherPriority

如果你簡單地排隊4個行動4以上範圍上DispatcherForeground隊列將首先執行,然後Background然後在最後的Idle隊列中執行。優先級0不會被執行。

現在你的代碼:

三個任務中排隊background月1日,在background第二和第三的​​隊列。所以3rd會先執行。那麼第二個任務會導致它優先於第一個任務。我希望清除它。

儘管一些觀測將幫助您喜歡更好地理解它,如果你已經設置的優先級爲7,8和9。所以,因爲這是一個前景隊列,7將得到第一個再執行7,然後8.一由一個並專門的順序,並同時得到執行7,8和9會等待,意味着​​隊列將得到同步執行到每個另一個。

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

希望這個解釋澄清在一定程度上。

+0

如果這是真的,屏幕上的顏色和文本的順序必須是「Three Two One」,而不是這種情況。 – 2016-09-27 10:44:29

+0

@ Vignesh.N我認爲你沒有仔細閱讀答案....任務在前臺隊列中,他們將在他們排隊的系列中執行。而產出將是「一二三」 – 2016-09-28 18:27:53