I was under the impression that the dispatcher
will follow the priority
of the operations queued it and execute the operations based on the priority
or the order in which the operation was added to the queue(if same priority)
until I was told that this is no the case in case of the WPF UI dispatcher
.
I was told that if a operation on the UI thread takes longer duration say a database read the UI dispatcher simple tries to execute next set of operations in the queue. I could not come to terms with it so decided to write a sample WPF application which contains a button and three rectangles, on click of the button, the rectangles are filled with different colors.
<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>
and in the 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");
}
}
The commented code works as expected the methods are invoked based on the DispatcherPriority
and I also get to see the screen refresh after each operation has been completed.
Order
is One, Two, Three
. Colors are drawn one after another.
Now the working code where the DispatcherPriority
is not mentioned
( I assume it would default to Normal
) the order is still One, Two, Three
but if I show a MessageBox
inside the methods, the
Thrid
popup is show first then Two
then One
but when I debug I could see the methods are
invoked in the expected order (IntelliTrace even shows that a message box is shown but I don't see it on the screen at that time and see it only after the last operation is finished.) its just that the MessageBox
es are shown in the reverse order.
Is it because MessageBox.Show
is a blocking call and the operation are cleared after the message has been closed.
Even then the order of the MessageBox
should also be One
, Two and
Three` ?