2015-05-06 2 views
0

У меня есть программа wpf, то, что я хочу сделать, это метод btnAnalyzer_click, чтобы подождать до тех пор, пока оба DoWork & RunWorkerCompleted не закончатся. Поэтому я использовал AutoResetEvent, но теперь метод bwAnalyze_click (строка # 4) запускается после DoWork, а затем с помощью метода WorkerCompleted (порядок строк - # 1 # 2 # 4 & # 3). Но я хочу, чтобы они выполнялись в порядке # 1 # 2 # 3 & # 4. Любые решения или предложения?Фоновый работник RunWorkCompleted Событие

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 
    } 
} 

ответ

2

Хотя ответы, предполагающие с помощью задач будет работать, я немного запутался в том, почему вы хотите подождать, пока работник фона завершит свою работу, прежде чем разрешить событие щелчка потока пользовательского интерфейса продолжить. Насколько я понимаю, вы используете фонового работника, потому что хотите выполнить фоновый режим, не блокируя пользовательский интерфейс. Способ, которым вы задали свой вопрос, предполагает, что вы хотите заблокировать пользовательский интерфейс, пока ваша работа не завершится. В этом случае зачем использовать отдельный поток?

Кроме того, что касается Вашего комментария:

autoReset.WaitOne();//when commented working properly 

Я предполагаю, что если вы оставите его раскомментирована, блоки интерфейса постоянно? Когда вы вызываете autoReset.WaitOne() в событии нажатия кнопки, вы блокируете поток пользовательского интерфейса. Пока DoWork будет работать в фоновом потоке, событие RunWorkerCompleted запускается в потоке пользовательского интерфейса. Поэтому RunWorkerCompleted никогда не сможет выполнить.

Если вы прокомментируете звонок WaitOne(), я не верю, что он будет работать «правильно» вообще. Я тестировал его, и он варьируется между кликом-> load-> completed и load-> click-> завершенным из-за гонки между нитью пользовательского интерфейса и фоновым потоком.

+0

Да, я понимаю вашу точку зрения, ожидание и использование фонового работника бесполезно. Я редактирую существующую базу кода, поэтому удаление фонового рабочего кажется большим количеством работы. Поэтому я попытался изменить порядок щелчка и завершить при использовании фонового рабочего. – maamaa

+0

Я вижу! Самый простой способ - переместить все после RunWorkerAsync в новый метод и вызвать это в WorkerCompleted() ... Тогда вам гарантировано, что он будет выполняться линейно, не блокируя ничего. Хотя я должен сказать, что немного чувствую, что код нужен для обслуживания :) – Rowbear

+0

@ Rowbear: Если вы редактируете существующий код, почему бы не улучшить дизайн, так как у вас есть шанс? :) ['" Оставьте уборщик кемпинга, чем тот, который вы его нашли. ") (Http://alvinalexander.com/programming/clean-code-quotes-robert-c-martin) –

1

Я думаю, следующее должно дать желаемое поведение -

private void btnAnalyze_Click(object sender, RoutedEventArgs e) 
{  

     Task.Factory.StartNew(() => { 

     }) 
     .ContinueWith(f => {    

     }) 
     .Wait(); 
} 
0

Большинство ответов здесь справедливо просят вас попробовать и сделать то, что вы хотите сделать с TPL, но если у вас сложный сценарий, где вам нужно использовать ManualResetEvent/AutoResetEvent, то вот решение проблемы. Просто объедините свою логику btn click в задаче или потоке. Идея заключалась в том, что вы не хотите удерживать основной пользовательский интерфейс (STA Main). Это приводит к некоторой оптимизации времени выполнения и приводит к нежелательному поведению.

Task.Factory.StartNew(() => 
      { 
       bwAnalyzer.RunWorkerAsync(); //#1 
       autoReset.WaitOne(); //when commented working properly 
       Console.WriteLine("click"); //#4 
      }); 

Только наличие выше фрагмента должно дать вам желаемое поведение.

Смежные вопросы