了解WPF Dispatcher.BeginInvoke

时间:2014-09-22 16:54:39

标签: c# wpf multithreading dispatcher

我的印象是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弹出窗口首先显示然后Two然后One但是当我调试时我可以看到方法是按预期的顺序调用的(IntelliTrace甚至显示一个消息框显示但是我没有看到它当时的屏幕,只有在最后一次操作完成后才能看到它。)只是MessageBox es以相反的顺序显示。

是否因为MessageBox.Show是阻止呼叫,并且在消息关闭后清除了操作。
即使这样,MessageBox的顺序也应该是OneTwo and三个??

1 个答案:

答案 0 :(得分:4)

在了解代码行为之前,先了解Dispatcher的优先级。 DispatcherPriority分为范围,如下图所示。

DispatcherPriority

如果您只是将4个操作排到Dispatcher上的4个以上范围。首先执行Foreground队列,然后执行Background,然后执行最后Idle队列。优先级0不会被执行。

现在您的代码:

三个任务在background排队第一,background排名第二,foreground排队第三排队。所以第3次将首先被执行。然后第二个任务导致它具有比第一个任务更高的优先级我希望能够清除它。

虽然更多观察将有助于您更好地理解它,如果您将优先级设置为7,8和9,那么如果这是一个前台队列,则先执行7然后执行7然后执行8。一个且完全按照该顺序执行,当7执行时,8和9将等待,这意味着foreground队列将彼此同步执行。

但是BackgroundIdle队列不会以这种方式执行,其中执行与其他任务异步,任务将遵循优先级。首先是BackgroundIdle队列。

希望这种解释在某种程度上得到澄清。