dispatcher
は、キューに入れられた操作の優先順位に従い、優先順位または操作がキューに追加された順序(同じ優先順位の場合)に基づいて、これがそうでないと言われるまで操作を実行するという印象を受けましたWPF UI dispatcher
の場合。
UIスレッドでの操作に時間がかかる場合、データベースがUIディスパッチャーを読み取ると、キュー内の次の一連の操作を実行しようとする、と言われました。私はそれに同意することができなかったので、ボタンと3つの長方形を含むサンプル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
に基づいて呼び出され、各操作が完了した後に画面が更新されることもわかります。 Order
はOne, Two, Three
です。色は次々に描かれます。
現在、DispatcherPriority
が記載されていない作業コード(デフォルトではNormal
であると仮定しています)の順序はまだOne, Two, Three
ですが、メソッド内にMessageBox
を表示すると、Thrid
ポップアップが最初に表示され、次にTwo
が表示され、次にOne
が表示されますが、デバッグするとメソッドが表示されます
期待される順序で呼び出されます(IntelliTraceはメッセージボックスが表示されていることを示していますが、その時点では画面に表示されず、最後の操作が終了した後にのみ表示されます)。それはMessageBox
es逆順で表示されます。
MessageBox.Show
はブロッキング呼び出しであり、メッセージが閉じられた後に操作がクリアされるためです。
それでも、MessageBox
の順序もOne
、Two and
Three`でなければなりませんか?
コードの動作を理解する前に、Dispatcher
の優先順位を理解することが前提条件です。 DispatcherPriority
は、下の画像に示すように範囲に分割されます。
Dispatcher
で上記の4つの範囲に4つのアクションを単純にキューイングする場合。 Foreground
キューが最初に実行され、次にBackground
が実行され、次に最後のIdle
キューが実行されます。優先度0は実行されません。
今あなたのコード:
3つのタスクは、background
で1番目、background
で2番目、foreground
キューで3番目にキューに入れられます。したがって、3番目が最初に実行されます。次に、2番目のタスクが1番目のタスクよりも高い優先度を持ちます。これで解決することを願っています。
優先順位を7,8および9に設定した場合はどうでしょうか。たとえば、これがフォアグラウンドキューであるため、7が最初に実行され、次に7、次に8が実行されます。その順序で、7が実行されている間、8と9は待機します。つまり、foreground
キューは互いに同期して実行されます。
ただし、Background
およびIdle
キューは、実行が他のタスクと非同期であり、タスクが優先順位に従っているような動作をしません。そして最初のBackground
とIdle
キュー。
この説明がある程度明確になることを願っています。
これは、最初のMessageBox
がIスレッドをブロックしているためです。
Dispatcher.BeginInvoke()
が内部で行うことは、デリゲートを取得し、次のアイドル期間中にメインUIスレッドで実行されるようにデリゲートをスケジュールすることです。ただし、MessageBox
は、閉じられるまで呼び出し元のスレッドをブロックします。つまり、2番目のMessageBox
は、最初のスレッドがクリアされるまで表示できないことを意味します。UIスレッドスケジューラは、スレッドが既に使用されていることを確認し(最初のMessageBox
がクリアされるのを待っている) t 2番目のMessageBox
を含む次のデリゲートを実行します。