我有以下wpf程序,我想做的是btnAnalyzer_click方法等待DoWork& RunWorkerCompleted方法完成。所以我使用了AutoResetEvent,但现在bwAnalyze_click方法(#4行)在DoWork之后运行,然后运行WorkerCompleted方法(行顺序 - #1#2#4&#3)。但是我希望它们按照#1#2#3&的顺序执行。 #4。任何解决方案或建议?
public partial class MainWindow : Window
{
private readonly BackgroundWorker bwAnalyzer = new BackgroundWorker();
private AutoResetEvent autoReset;//to signal the end of the BackgroudnWork
public MainWindow()
{
InitializeComponent();
autoReset = new AutoResetEvent(false);
bwAnalyzer.DoWork += new DoWorkEventHandler(DoWork);
bwAnalyzer.RunWorkerCompleted += new RunWorkerCompletedEventHandler(WorkerCompleted);
}
void WorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
Console.WriteLine("Completed"); #3
autoReset.Set();
}
void DoWork(object sender, DoWorkEventArgs e)
{
Console.WriteLine("load"); #2
}
private void btnAnalyze_Click(object sender, RoutedEventArgs e)
{
bwAnalyzer.RunWorkerAsync(); #1
autoReset.WaitOne();//when commented working properly
Console.WriteLine("click"); #4
}
}
答案 0 :(得分:2)
虽然建议使用Tasks的答案可行,但我有点困惑为什么要等到后台工作人员完成其工作之后才让UI线程的点击事件继续。据我所知,您使用后台工作程序,因为您希望在不阻止UI的情况下执行后台工作。您提出问题的方式表明您希望在工作完成之前阻止UI。在这种情况下,为什么要使用单独的线程?
另外,关于你的评论:
autoReset.WaitOne();//when commented working properly
我假设如果您将其取消注释,UI会永久阻止?当您在按钮的单击事件中调用autoReset.WaitOne()
时,您将阻止UI线程。虽然DoWork
将在后台线程上运行,但RunWorkerCompleted
事件在UI线程上运行。因此RunWorkerCompleted永远不会执行。
如果您对WaitOne()
来电发表评论,我认为它根本不会“正常”发挥作用。我测试了它,并且由于UI线程和后台线程之间的竞争而在click-> load-> completed和load-> click->完成之间变化。
答案 1 :(得分:1)
使用任务,并使用ContinueWith方法:https://msdn.microsoft.com/en-us/library/dd270696(v=vs.110).aspx
答案 2 :(得分:1)
我想以下内容应该给出所需的行为 -
private void btnAnalyze_Click(object sender, RoutedEventArgs e)
{
Task.Factory.StartNew(() => {
})
.ContinueWith(f => {
})
.Wait();
}
答案 3 :(得分:0)
这里的大多数答案都正确地要求您尝试使用TPL做您想做的事情,但如果您有一个复杂的场景,您需要使用ManualResetEvent / AutoResetEvent,那么这里就是解决您问题的方法。 只需在任务或线程中包含您的btn click逻辑。想法是你不想持有UI(STA Main)线程。这导致一些运行时优化并导致不期望的行为。
write.table(...)
只要拥有上述代码段就可以为您提供所需的行为。