2011-12-02 85 views
2

我想创建一个DispatcherObject的子类来创建我自己的具有消息队列的线程关联对象,就像WPF用于UI元素一样。继承自DispatcherObject

我有一个测试应用程序运行时没有崩溃,但DispatcherObject似乎没有处理它的消息队列。我刚刚创建了一个新的空白WPF应用程序,并添加以下代码到MainWindow.xaml.cs

public partial class MainWindow : Window { 
    public MainWindow() { 
     InitializeComponent(); 

     DispatcherWorker worker = null; 
     ManualResetEventSlim latch = new ManualResetEventSlim(false); 

     new Thread(() => { 
      worker = new DispatcherWorker(); 
      latch.Set(); 
     }).Start(); 

     latch.Wait(); 

     // worker.Dispatcher.Thread is stopped by here... why? 
     worker.Dispatcher.BeginInvoke(new Action(() => { 
      // This code never executed 
      worker.DoWork(this); 
     })); 
    } 
} 

public class DispatcherWorker : DispatcherObject { 

    public void DoWork(MainWindow window) { 
     VerifyAccess(); 
     window.Dispatcher.BeginInvoke(new Action(() => window.Background = Brushes.Black)); 
    } 
} 

永远不会执行该DoWork()方法,如果我把一个断点只是调用之前BeginInvoke,我看到了Dispatcher的线程停止。为什么停止?我是否设置了线程错误? (This similar question似乎也有同样的问题,但接受的答案表示在一个GUI应用程序中运行代码,这将有一个消息泵,但即使在GUI应用程序中运行,我也遇到同样的问题。 )

+0

我不知道有关线程或你在做什么,但是不会有'.Wait()'调用挂起线程直到某些事情完成,但是某些事情永远不会开始或完成,因为主UI线程正在等待构造函数完成? – Rachel

+0

@Rachel:'Wait()'调用只会等到'ManualResetEventSlim。Set()'调用,这发生在另一个线程上。当我遍历代码时,我可以完全通过构造函数,只是对'worker.Dispatcher.BeginInvoke'的调用没有效果。 –

回答

3

拥有该Dispatcher需要“泵”是Dispatcher线程的详细信息。也就是说,它需要被告知处理通过Dispatcher排队的消息。要做到这一点,您可以使用一个DispatcherFrame

Dispatcher.PushFrame(new DispatcherFrame()); 

您设置的锁后,这应该会出现。该线程永远不会退出 - 它只会在该线程的调度程序上抽取消息。如果您希望它具有退出条件,请参阅DispatcherFrameContinue属性的文档。

请注意,使用自定义的DispatcherWorker类还是其他内置的WPF类是无关紧要的。如果在该线程上没有任何信息Dispatcher,则不会处理消息。

+1

做同样事情的另一种方法是调用Dispatcher.Run()。 – AndrewS

2

我想这是因为worker.Dispatcher指的是DispatcherObject(在这种情况下,DispatcherWorker)上创建线程,这将是在构造函数中创建的Thread

由于该线程已经启动并完成工作,当前状态为Stopped。你可能不得不再次启动它运行DoWork()

你可以找到关于这个问题here

0

事实上,你已经创建了一个线程。并且您的DispatcherWorker在创建的线程的范围内实例化,这使您创建DispatcherWorker的CurrentThread的线程成为可能。

因此,在BeginInvoke中,DispatcherWorker发生中断,因为PostMessage(“user32.dll”)不会从DispatcherWorker中抽取消息。如果您的工作人员在创建的线程范围之外实例化,那么所有工作都会顺利进行,因为他的调度员是主线程调度员。

总之,您的工作人员被贬低是因为在BeginInvoke中没有可能抽取消息。