为什么第二个UI线程会冻结第一个?

时间:2011-10-23 09:03:42

标签: wpf multithreading

我有一个有两个UI线程和一个后台工作程序的应用程序。一切正常,除了在第二个模拟UI线程中处理ProgressChanged阻塞第一个。为什么会这样?我该如何解决这个问题(我想要阻止第二个而不是主UI线程)?

MainWindow类的一部分:

private SimulationWindow simulationWindow;

    public MainWindow()
    {
        InitializeComponent();
        Thread thread = new Thread(() =>
        {
            simulationWindow = new SimulationWindow();
            simulationWindow.Show();
            simulationWindow.Closed += (sender2, e2) =>
                      simulationWindow.Dispatcher.InvokeShutdown();
            Dispatcher.Run();
        });
        thread.SetApartmentState(ApartmentState.STA);
        thread.Start();
    }

    private void start_Click(object sender, RoutedEventArgs e)
    {
        simulationWindow.Start();
    }

SimulationWindow类的一部分:

private BackgroundWorker bw;

public SimulationWindow()
{
    InitializeComponent();
    bw = new BackgroundWorker() { WorkerReportsProgress = true, WorkerSupportsCancellation = true };
    bw.DoWork += new DoWorkEventHandler(bw_DoWork);
    bw.ProgressChanged += new ProgressChangedEventHandler(bw_ProgressChanged);
    bw.RunWorkerCompleted += new RunWorkerCompletedEventHandler(bw_RunWorkerCompleted);
}

void bw_DoWork(object sender, DoWorkEventArgs e)
{
    //some complex computation will go here
    //Thread.Sleep(10000); <- both windows responsive, OK
    bw.ReportProgress(0);
}


void bw_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
    //some complex rendering will go here
    Thread.Sleep(10000); // this blocks main UI thread, why?
}

public void Start()
{
    bw.RunWorkerAsync();
}

private void doSth_Click(object sender, RoutedEventArgs e)
{
    Thread.Sleep(10000); // freezes simulationWindow, which was understandable
}

1 个答案:

答案 0 :(得分:6)

您在主UI线程上调用simulationWindow.Start()。这意味着BW在该线程上启动,这意味着它捕获主UI线程的SynchronizationContext,因此也在该线程上引发ProgressChanged

您需要将对bw.RunWorkerAsync()的调用封送到您的第二个帖子。您可以通过调用SimulationWindow.Start()并将this.Dispatcher.Invoke作为代理人在bw.RunWorkerAsync()中执行此操作。然后它应该在你的第二个窗口线程上运行,并且将在该线程上引发事件。