2015-05-06 133 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

雖然答案使用任務將工作建議,我有些困惑,你爲什麼要等到後臺工作者完成工作,然後再讓UI線程的點擊事件繼續下去。據我所知,你使用後臺工作者,因爲你想在不阻礙用戶界面的情況下執行後臺工作。你問你的問題的方式表明你想阻止用戶界面,直到你的工作完成。在那種情況下,爲什麼要使用單獨的線程呢?

此外,關於您的評論:

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

我假設,如果你離開它註釋掉,在UI塊永久?當您在按鈕的單擊事件中調用autoReset.WaitOne()時,您將阻止UI線程。雖然DoWork將在後臺線程上運行,但RunWorkerCompleted事件將在UI線程上運行。因此RunWorkerCompleted將永遠不會執行。

如果您評論WaitOne()電話,我認爲它不會「正常」工作。我對它進行了測試,由於UI線程和後臺線程之間的競爭,點擊 - >加載 - >完成和加載 - >點擊 - >完成。

+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點擊邏輯即可。這個想法是你不想保持UI(STA Main)線程。這會導致一些運行時優化並導致不希望的行爲。

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

只要有上面的代碼段應該給你想要的行爲。