我有一个有两个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
}
答案 0 :(得分:6)
您在主UI线程上调用simulationWindow.Start()
。这意味着BW在该线程上启动,这意味着它捕获主UI线程的SynchronizationContext
,因此也在该线程上引发ProgressChanged
。
您需要将对bw.RunWorkerAsync()
的调用封送到您的第二个帖子。您可以通过调用SimulationWindow.Start()
并将this.Dispatcher.Invoke
作为代理人在bw.RunWorkerAsync()
中执行此操作。然后它应该在你的第二个窗口线程上运行,并且将在该线程上引发事件。