2014-09-22 88 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

相关问题