[英]Exception handling inside “async void” WPF command handlers
我正在審查我的同事的一些WPF代碼,這是一個基於UserControl
的組件庫 ,包含許多async void
事件和命令處理程序。 這些方法目前不在內部實現任何錯誤處理 。
代碼簡而言之:
<Window.CommandBindings>
<CommandBinding
Command="ApplicationCommands.New"
Executed="NewCommand_Executed"/>
</Window.CommandBindings>
private async void NewCommand_Executed(object sender, ExecutedRoutedEventArgs e)
{
// do some fake async work (and may throw if timeout < -1)
var timeout = new Random(Environment.TickCount).Next(-100, 100);
await Task.Delay(timeout);
}
拋出異常但在NewCommand_Executed
未觀察到的異常只能在全局級別上處理 (例如,使用AppDomain.CurrentDomain.UnhandledException
)。 顯然,這不是一個好主意。
我可以在本地處理異常:
private async void NewCommand_Executed(object sender, ExecutedRoutedEventArgs e)
{
try
{
// do some fake async work (throws if timeout < -1)
var timeout = new Random(Environment.TickCount).Next(-100, 100);
await Task.Delay(timeout);
}
catch (Exception ex)
{
// somehow log and report the error
MessageBox.Show(ex.Message);
}
}
但是,在這種情況下,主機應用程序的ViewModel將不會意識到 NewCommand_Executed
的錯誤 。 也不是理想的解決方案,加上錯誤報告UI不應該總是作為庫代碼的一部分。
另一種方法是在本地處理它們並觸發一個專門的錯誤事件:
public class AsyncErrorEventArgs: EventArgs
{
public object Sender { get; internal set; }
public ExecutedRoutedEventArgs Args { get; internal set; }
public ExceptionDispatchInfo ExceptionInfo { get; internal set; }
}
public delegate void AsyncErrorEventHandler(object sender, AsyncErrorEventArgs e);
public event AsyncErrorEventHandler AsyncErrorEvent;
private async void NewCommand_Executed(object sender, ExecutedRoutedEventArgs e)
{
ExceptionDispatchInfo exceptionInfo = null;
try
{
// do some fake async work (throws if timeout < -1)
var timeout = new Random(Environment.TickCount).Next(-100, 100);
await Task.Delay(timeout);
}
catch (Exception ex)
{
// capture the error
exceptionInfo = ExceptionDispatchInfo.Capture(ex);
}
if (exceptionInfo != null && this.AsyncErrorEvent != null)
this.AsyncErrorEvent(sender, new AsyncErrorEventArgs {
Sender = this, Args = e, ExceptionInfo = exceptionInfo });
}
我最喜歡最后一個,但我很欣賞任何其他建議,因為我對WPF的體驗有限。
是否存在已建立的WPF模式以將錯誤從async void
命令處理程序傳播到ViewModal?
在WPF命令處理程序中執行異步工作通常是一個壞主意 ,因為它們可能用於快速同步UI更新?
我在WPF的上下文中問這個問題,但我認為它也適用於WinForms中的async void
事件處理程序。
這里的問題是您的UserControl庫沒有以典型的MVVM方式構建。 通常,對於非平凡的命令,您的UserControl的代碼不會直接綁定到命令,而是具有在設置(通過綁定到ViewModel)時將觸發控件中的操作的屬性。 然后,您的ViewModel將綁定到應用程序命令,並設置適當的屬性。 (或者,您的MVVM框架可能有另一個消息傳遞方案,可用於ViewModel和View之間的交互)。
至於在UI中拋出的異常,我再次感覺存在架構問題。 如果UserControl做的不僅僅是充當View,(即運行可能導致意外異常的任何類型的業務邏輯),那么這應該分為View和ViewModel。 ViewModel將運行邏輯,可以由其他應用程序ViewModel實例化,也可以通過其他方法進行通信(如上所述)。
如果UserControl的布局/可視化代碼拋出異常,則ViewModel不會以任何方式捕獲(幾乎無例外)。 正如您所提到的,這應該僅由全局級別處理程序進行日志記錄處理。
最后,如果Control的代碼中確實存在已知的“異常”,則需要通知您的ViewModel,我建議捕獲已知異常並引發事件/命令並設置屬性。 但同樣,這不應該用於例外,只是預期的“錯誤”狀態。
在我看來,用戶幾乎100%不知道的異常的傳播並不是一個好習慣。 看到這個
我看到了你真正擁有的兩個選項,因為WPF沒有提供任何開箱即用的機制來通知任何問題:
總而言之,你必須為這樣的代碼編寫一些xml-comments,因為這並不容易理解。 最重要的是你不應該(幾乎)從任何輔助線程拋出任何異常。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.