2017-07-25 237 views
0

我有一個孩子的形式推出形式父形式:WPF子窗體,OnClosing事件和等待

ConfigForm cfg = new ConfigForm(); 
cfg.ShowDialog(); 

這個孩子的形式來配置一些應用參數。 我想檢查是否有一些更改未保存,如果有,請警告用戶。 所以我在OnClosing事件的聲明是這樣的:

private async void ChildFormClosing(object sender, System.ComponentModel.CancelEventArgs e) 
{ 
    // Here i call a function that compare the current config with the saved config 
    bool isUptated = CheckUnsavedChanges(); 

    // If updated is false, it means that there are unsaved changes... 
    if (!isUpdated) 
    { 
     e.Cancel = true; 

     // At this point i create a MessageDialog (Mahapps) to warn the user about unsaved changes... 
     MessageDialogStyle style = MessageDialogStyle.AffirmativeAndNegative; 

     var metroDialogSettings = new MetroDialogSettings() 
     { 
      AffirmativeButtonText = "Close", 
      NegativeButtonText = "Cancel" 
     }; 

     var result = await this.ShowMessageAsync("Config", "There are unsaved changes, do you want to exit?", style, metroDialogSettings); 

     // If we press Close, we want to close child form and go back to parent... 
     if (result == MessageDialogResult.Affirmative) 
     { 
      e.Cancel = false; 
     } 
    } 
} 

我的邏輯說,如果我宣佈e.cancel爲false,將繼續關閉的形式,但它不會發生,子窗體保持打開狀態。

我的猜測是,異步調用是做一些我不明白,因爲如果我用這種方式宣告ChildFormClosing:

private async void ChildFormClosing(object sender, System.ComponentModel.CancelEventArgs e) 
{ 
    bool isUptated = CheckUnsavedChanges(); 

    e.Cancel = true; 

    if (!isUpdated) 
    { 
     MessageDialogStyle style = MessageDialogStyle.AffirmativeAndNegative; 

     var metroDialogSettings = new MetroDialogSettings() 
     { 
      AffirmativeButtonText = "Close", 
      NegativeButtonText = "Cancel" 
     }; 

     var result = await this.ShowMessageAsync("Config", "There are unsaved changes, do you want to exit?", style, metroDialogSettings); 

     if (result == MessageDialogResult.Affirmative) 
     { 
      e.Cancel = false; 
     } 
    } 
    else 
    { 
     e.Cancel = false; 
    } 
} 

最後否則e.Cancel =虛假工程和子窗體關閉...

任何線索? 謝謝!

+0

爲什麼你需要異步顯示消息?既然你是在窗口的事件處理程序中,不應該在UI線程上呢? – Andy

+0

@Andy你是對的...如果我更改ShowModalMessageExternal(不是異步方法)ShowMessageAsync問題已修復。儘管這並不能解釋這種奇怪的行爲(我想知道究竟發生了什麼,你知道......),如果你發表評論作爲答案,我將非常樂意將它標記爲好的。謝謝! –

回答

4

由於此方法是窗口的事件處理程序,因此它將在UI線程上被調用,因此不需要異步顯示消息框。

至於你看到的奇怪行爲,這與事件處理程序中的await有關。當你調用await的一個方法時,實際發生的是直到await一切正常執行,但是一旦await語句被達到控制權返回給調用者。一旦返回的方法是await,則執行原始方法的其餘部分。

觸發OnClosing事件的代碼可能沒有考慮到異步事件處理程序的設計,因此它假定如果事件處理程序返回,它已完成需要執行的任何工作。由於您的事件處理函數在方法調用之前將CancelEventArgs.Cancel設置爲true,因此事件處理函數的調用者將其設置爲true,因此它不會關閉表單。

這就是爲什麼同步顯示消息框的原因:整個方法在控制權返回給調用者之前執行,因此CancelEventArgs.Cancel始終設置爲其預期值。

Raymond Chen最近發佈了兩篇關於async的文章,可能會有興趣閱讀:Crash course in async and awaitThe perils of async void。第二篇文章描述了爲什麼async事件處理程序往往無法按照您期望的方式工作。

+0

非常感謝您的解釋! –