在 UI 线程中执行的异步方法中的异常使应用程序崩溃
Exception in async method executing in UI-thread crashes application
当我 await
处理抛出异常的方法时,try/catch 无法避免应用程序崩溃。
有投掷方法
void CurrentStep.Process(CancellationToken cancellationToken)
{
throw new Exception();
}
通过ICommand.Execute()
从UI线程调用
ProcessCurrentStepCommand = AsyncCommandFactory.Create(async cancellationToken =>
{
try
{
await Task.Run(() => CurrentStep.Process(cancellationToken));
}
catch {}
CurrentStep = CurrentStep.NextStepViewModel;
});
ProcessCurrentStepCommand
绑定到 UI 上的按钮。当我单击该按钮时,我的应用程序中断了。
我觉得在 UI 线程上抛出异常是一个普遍的问题,但同时我不明白为什么 catch 块不能使我免于异常。
我现在找到了唯一适合我的方法:
await Task.Factory.StartNew(
action: () => CurrentStep.Process(cancellationToken),
creationOptions: TaskCreationOptions.LongRunning);
但是看起来很难看。如果我将来忘记我想用这段代码做什么,我可能会认为我需要清理它并遇到一些异常导致整个应用程序崩溃的麻烦。
在调试模式下,一切都很好。
- 原始中断异常源。
Call stack:
UI.exe!UI.Steps.ViewModels.SvmConnectionViewModel.Process(System.Threading.CancellationToken
cancellationToken)
UI.exe!UI.MainViewModel..ctor.AnonymousMethod__1() Line 18
mscorlib.dll!System.Threading.Tasks.Task.InnerInvoke() Line 2911
mscorlib.dll!System.Threading.Tasks.Task.Execute() Line 2523
mscorlib.dll!System.Threading.Tasks.Task.ExecutionContextCallback(object
obj) Line 2888
mscorlib.dll!System.Threading.ExecutionContext.RunInternal(System.Threading.ExecutionContext
executionContext, System.Threading.ContextCallback callback, object
state, bool preserveSyncCtx) Line 581
mscorlib.dll!System.Threading.ExecutionContext.Run(System.Threading.ExecutionContext
executionContext, System.Threading.ContextCallback callback, object
state, bool preserveSyncCtx) Line 531
mscorlib.dll!System.Threading.Tasks.Task.ExecuteWithThreadLocal(ref System.Threading.Tasks.Task currentTaskSlot) Line 2853
mscorlib.dll!System.Threading.Tasks.Task.ExecuteEntry(bool bPreventDoubleExecution) Line 2792
mscorlib.dll!System.Threading.Tasks.Task.System.Threading.IThreadPoolWorkItem.ExecuteWorkItem()
Line 2729
mscorlib.dll!System.Threading.ThreadPoolWorkQueue.Dispatch() Line 830
mscorlib.dll!System.Threading._ThreadPoolWaitCallback.PerformWaitCallback()
Line 1171
- 下一次中断发生在 TaskAwaiter.cs 方法 ThrowForNonSuccess() 中:
NotImplementedException occured: A first chance exception of type 'System.NotImplementedException' occurred in mscorlib.dll
。
Call stack:
mscorlib.dll!System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(System.Threading.Tasks.Task
task) Line 180
mscorlib.dll!System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(System.Threading.Tasks.Task
task) Line 170
mscorlib.dll!System.Runtime.CompilerServices.TaskAwaiter.GetResult()
Line 125
UI.exe!UI.MainViewModel..ctor(System.Threading.CancellationToken cancellationToken) Line 18
[Resuming Async Method]
mscorlib.dll!System.Runtime.CompilerServices.AsyncMethodBuilderCore.MoveNextRunner.InvokeMoveNext(object
stateMachine) Line 1065
mscorlib.dll!System.Threading.ExecutionContext.RunInternal(System.Threading.ExecutionContext
executionContext, System.Threading.ContextCallback callback, object
state, bool preserveSyncCtx) Line 581
mscorlib.dll!System.Threading.ExecutionContext.Run(System.Threading.ExecutionContext
executionContext, System.Threading.ContextCallback callback, object
state, bool preserveSyncCtx) Line 531
mscorlib.dll!System.Runtime.CompilerServices.AsyncMethodBuilderCore.MoveNextRunner.Run()
Line 1045
mscorlib.dll!System.Runtime.CompilerServices.AsyncMethodBuilderCore.OutputAsyncCausalityEvents>.AnonymousMethod__0()
Line 973
mscorlib.dll!System.Runtime.CompilerServices.AsyncMethodBuilderCore.ContinuationWrapper.Invoke()
Line 1085
mscorlib.dll!System.Runtime.CompilerServices.TaskAwaiter.OutputWaitEtwEvents.AnonymousMethod__0()
Line 301
mscorlib.dll!System.Runtime.CompilerServices.AsyncMethodBuilderCore.ContinuationWrapper.Invoke()
Line 1085
mscorlib.dll!System.Threading.Tasks.SynchronizationContextAwaitTaskContinuation.GetActionLogDelegate.AnonymousMethod__3()
Line 470
mscorlib.dll!System.Threading.Tasks.SynchronizationContextAwaitTaskContinuation..cctor.AnonymousMethod__6(object
state) Line 393
WindowsBase.dll!System.Windows.Threading.ExceptionWrapper.InternalRealCall(System.Delegate
callback, object args, int numArgs) Line 118 Unknown
WindowsBase.dll!MS.Internal.Threading.ExceptionFilterHelper.TryCatchWhen(object
source, System.Delegate method, object args, int numArgs,
System.Delegate catchHandler) Line 41 Unknown
WindowsBase.dll!System.Windows.Threading.DispatcherOperation.InvokeImpl()
Line 583 Unknown
WindowsBase.dll!System.Windows.Threading.DispatcherOperation.InvokeInSecurityContext(object
state) Line 528 Unknown
mscorlib.dll!System.Threading.ExecutionContext.RunInternal(System.Threading.ExecutionContext
executionContext, System.Threading.ContextCallback callback, object
state, bool preserveSyncCtx) Line 581
mscorlib.dll!System.Threading.ExecutionContext.Run(System.Threading.ExecutionContext
executionContext, System.Threading.ContextCallback callback, object
state, bool preserveSyncCtx) Line 531
mscorlib.dll!System.Threading.ExecutionContext.Run(System.Threading.ExecutionContext
executionContext, System.Threading.ContextCallback callback, object
state) Line 520
WindowsBase.dll!System.Windows.Threading.DispatcherOperation.Invoke()
Line 441 Unknown
WindowsBase.dll!System.Windows.Threading.Dispatcher.ProcessQueue() Line 2227 Unknown
WindowsBase.dll!System.Windows.Threading.Dispatcher.WndProcHook(System.IntPtr
hwnd, int msg, System.IntPtr wParam, System.IntPtr lParam, ref bool
handled) Line 2480 Unknown
WindowsBase.dll!MS.Win32.HwndWrapper.WndProc(System.IntPtr hwnd, int msg, System.IntPtr wParam, System.IntPtr lParam, ref bool handled)
Line 345 Unknown
WindowsBase.dll!MS.Win32.HwndSubclass.DispatcherCallbackOperation(object
o) Line 494 Unknown
WindowsBase.dll!System.Windows.Threading.ExceptionWrapper.InternalRealCall(System.Delegate
callback, object args, int numArgs) Line 111 Unknown
WindowsBase.dll!MS.Internal.Threading.ExceptionFilterHelper.TryCatchWhen(object
source, System.Delegate method, object args, int numArgs,
System.Delegate catchHandler) Line 41 Unknown
WindowsBase.dll!System.Windows.Threading.Dispatcher.LegacyInvokeImpl(System.Windows.Threading.DispatcherPriority
priority, System.TimeSpan timeout, System.Delegate method, object
args, int numArgs) Line 1447 Unknown
WindowsBase.dll!MS.Win32.HwndSubclass.SubclassWndProc(System.IntPtr hwnd, int msg, System.IntPtr wParam, System.IntPtr lParam) Line
398 Unknown
[Native to Managed Transition]
[Managed to Native Transition]
WindowsBase.dll!System.Windows.Threading.Dispatcher.PushFrameImpl(System.Windows.Threading.DispatcherFrame
frame) Line 2281 Unknown
WindowsBase.dll!System.Windows.Threading.Dispatcher.PushFrame(System.Windows.Threading.DispatcherFrame
frame) Line 369 Unknown
WindowsBase.dll!System.Windows.Threading.Dispatcher.Run() Line 328 Unknown
PresentationFramework.dll!System.Windows.Application.RunDispatcher(object
ignore) Line 2745
PresentationFramework.dll!System.Windows.Application.RunInternal(System.Windows.Window
window) Line 1841
PresentationFramework.dll!System.Windows.Application.Run(System.Windows.Window
window) Line 261
PresentationFramework.dll!System.Windows.Application.Run() Line 222 UI.exe!UI.App.Main()
[Native to Managed Transition]
mscorlib.dll!System.AppDomain.ExecuteAssembly(string assemblyFile, System.Security.Policy.Evidence assemblySecurity, string[] args) Line
2031
Microsoft.VisualStudio.HostingProcess.Utilities.dll!Microsoft.VisualStudio.HostingProcess.HostProc.RunUsersAssembly() Unknown
mscorlib.dll!System.Threading.ThreadHelper.ThreadStart_Context(object
state) Line 74
mscorlib.dll!System.Threading.ExecutionContext.RunInternal(System.Threading.ExecutionContext
executionContext, System.Threading.ContextCallback callback, object
state, bool preserveSyncCtx) Line 581
mscorlib.dll!System.Threading.ExecutionContext.Run(System.Threading.ExecutionContext
executionContext, System.Threading.ContextCallback callback, object
state, bool preserveSyncCtx) Line 531
mscorlib.dll!System.Threading.ExecutionContext.Run(System.Threading.ExecutionContext
executionContext, System.Threading.ContextCallback callback, object
state) Line 520
mscorlib.dll!System.Threading.ThreadHelper.ThreadStart() Line 111
[Async Call]
UI.exe!UI.Commands.AsyncCommandFactory.Create(System.Threading.CancellationToken
token) Line 27
[Async Call]
UI.exe!UI.NotifyTaskCompletion.WatchTaskAsync(System.Threading.Tasks.Task
task) Line 66
[Async Call]
UI.exe!UI.Commands.AsyncCommand.ExecuteAsync(object parameter) Line 55
[Async Call]
UI.exe!UI.Commands.AsyncCommandBase.Execute(object parameter) Line 15
- 下一个中断具有相同的异常并且与之前的堆栈跟踪几乎相同(不同之处仅在于最后调用的 4 个方法中的第一个)。
Call stack:
mscorlib.dll!System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(System.Threading.Tasks.Task
task) Line 180
mscorlib.dll!System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(System.Threading.Tasks.Task
task) Line 170
mscorlib.dll!System.Runtime.CompilerServices.TaskAwaiter.GetResult()
Line 125
UI.exe!UI.Commands.AsyncCommandFactory.Create(System.Threading.CancellationToken token) Line 27
[Resuming Async Method]
...
- 下一个又是方法不同而已
Call stack:
mscorlib.dll!System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(System.Threading.Tasks.Task
task) Line 180
mscorlib.dll!System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(System.Threading.Tasks.Task
task) Line 170
mscorlib.dll!System.Runtime.CompilerServices.TaskAwaiter.GetResult()
Line 125
UI.exe!UI.NotifyTaskCompletion.WatchTaskAsync(System.Threading.Tasks.Task task) Line 66
[Resuming Async Method]
...
- 在之前的中断之后,没有再引发异常并且 Task.IsFaulted 设置为 true。现在 UI 使用此绑定成功显示异常消息:
<Label Content="{Binding ProcessCurrentStepCommand.Execution.ErrorMessage}" Visibility="{Binding ProcessCurrentStepCommand.Execution.IsFaulted, Converter={StaticResource BooleanToVisibilityConverter}}" />
最终编辑。
要了解问题的背景和接受的答案,您需要查看这些文章:
I don’t want to propagate exceptions directly back to the main UI loop; I want to capture any exceptions and set properties so that the error handling is done via data binding.
那样的话,你真正需要的是一个synchronous命令,它只是starts异步操作,这里表示异步操作使用 NotifyTaskCompletion
(或您编写的某种类似类型)。像这样分解操作(分为同步 "start" 和异步数据绑定)比尝试将所有操作都集中在一起更容易(这也是可能的 - 只是代码不那么短或可重用):
// Represents the execution of the current step.
NotifyTaskCompletion ProcessCurrentStepCommandExecution
{
get { return _processCurrentStepCommandExecution; }
set { _processCurrentStepCommandExecution = value; PropertyChanged(); }
}
...
var cancellationToken = ...; // Wherever you get this from.
ProcessCurrentStepCommand = new DelegateCommand(() =>
{
ProcessCurrentStepCommandExecution = new NotifyTaskCompletion(async () =>
{
await Task.Run(() => CurrentStep.Process(cancellationToken));
// I'm assuming here you only want to move to the next step if there are no errors.
// Otherwise, this should be in a finally block.
CurrentStep = CurrentStep.NextStepViewModel;
});
});
编辑:
我相信您可能 运行 陷入了那篇文章的示例代码中的错误(在 MSDNMag 决定删除所有代码之前,评论中曾经更新过代码,我正在努力获取代码示例已更新,这是一个令人惊讶的漫长过程)。如果任务同步完成(异常或成功),则会出现错误;在这种情况下,NotifyTaskCompletion<T>.TaskCompleted
将是 null
。
要解决此问题,请将 NotifyTaskCompletion<T>
的构造函数更改为:
{
Task = task;
if (!task.IsCompleted)
TaskCompletion = WatchTaskAsync(task);
}
对此:
{
Task = task;
TaskCompletion = WatchTaskAsync(task);
}
当我 await
处理抛出异常的方法时,try/catch 无法避免应用程序崩溃。
有投掷方法
void CurrentStep.Process(CancellationToken cancellationToken)
{
throw new Exception();
}
通过ICommand.Execute()
ProcessCurrentStepCommand = AsyncCommandFactory.Create(async cancellationToken =>
{
try
{
await Task.Run(() => CurrentStep.Process(cancellationToken));
}
catch {}
CurrentStep = CurrentStep.NextStepViewModel;
});
ProcessCurrentStepCommand
绑定到 UI 上的按钮。当我单击该按钮时,我的应用程序中断了。
我觉得在 UI 线程上抛出异常是一个普遍的问题,但同时我不明白为什么 catch 块不能使我免于异常。
我现在找到了唯一适合我的方法:
await Task.Factory.StartNew(
action: () => CurrentStep.Process(cancellationToken),
creationOptions: TaskCreationOptions.LongRunning);
但是看起来很难看。如果我将来忘记我想用这段代码做什么,我可能会认为我需要清理它并遇到一些异常导致整个应用程序崩溃的麻烦。
在调试模式下,一切都很好。
- 原始中断异常源。
Call stack:
UI.exe!UI.Steps.ViewModels.SvmConnectionViewModel.Process(System.Threading.CancellationToken cancellationToken)
UI.exe!UI.MainViewModel..ctor.AnonymousMethod__1() Line 18 mscorlib.dll!System.Threading.Tasks.Task.InnerInvoke() Line 2911 mscorlib.dll!System.Threading.Tasks.Task.Execute() Line 2523 mscorlib.dll!System.Threading.Tasks.Task.ExecutionContextCallback(object obj) Line 2888 mscorlib.dll!System.Threading.ExecutionContext.RunInternal(System.Threading.ExecutionContext executionContext, System.Threading.ContextCallback callback, object state, bool preserveSyncCtx) Line 581
mscorlib.dll!System.Threading.ExecutionContext.Run(System.Threading.ExecutionContext executionContext, System.Threading.ContextCallback callback, object state, bool preserveSyncCtx) Line 531
mscorlib.dll!System.Threading.Tasks.Task.ExecuteWithThreadLocal(ref System.Threading.Tasks.Task currentTaskSlot) Line 2853 mscorlib.dll!System.Threading.Tasks.Task.ExecuteEntry(bool bPreventDoubleExecution) Line 2792 mscorlib.dll!System.Threading.Tasks.Task.System.Threading.IThreadPoolWorkItem.ExecuteWorkItem() Line 2729
mscorlib.dll!System.Threading.ThreadPoolWorkQueue.Dispatch() Line 830 mscorlib.dll!System.Threading._ThreadPoolWaitCallback.PerformWaitCallback() Line 1171
- 下一次中断发生在 TaskAwaiter.cs 方法 ThrowForNonSuccess() 中:
NotImplementedException occured: A first chance exception of type 'System.NotImplementedException' occurred in mscorlib.dll
。
Call stack:
mscorlib.dll!System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(System.Threading.Tasks.Task task) Line 180
mscorlib.dll!System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(System.Threading.Tasks.Task task) Line 170
mscorlib.dll!System.Runtime.CompilerServices.TaskAwaiter.GetResult() Line 125
UI.exe!UI.MainViewModel..ctor(System.Threading.CancellationToken cancellationToken) Line 18
[Resuming Async Method]
mscorlib.dll!System.Runtime.CompilerServices.AsyncMethodBuilderCore.MoveNextRunner.InvokeMoveNext(object stateMachine) Line 1065
mscorlib.dll!System.Threading.ExecutionContext.RunInternal(System.Threading.ExecutionContext executionContext, System.Threading.ContextCallback callback, object state, bool preserveSyncCtx) Line 581
mscorlib.dll!System.Threading.ExecutionContext.Run(System.Threading.ExecutionContext executionContext, System.Threading.ContextCallback callback, object state, bool preserveSyncCtx) Line 531
mscorlib.dll!System.Runtime.CompilerServices.AsyncMethodBuilderCore.MoveNextRunner.Run() Line 1045
mscorlib.dll!System.Runtime.CompilerServices.AsyncMethodBuilderCore.OutputAsyncCausalityEvents>.AnonymousMethod__0() Line 973
mscorlib.dll!System.Runtime.CompilerServices.AsyncMethodBuilderCore.ContinuationWrapper.Invoke() Line 1085
mscorlib.dll!System.Runtime.CompilerServices.TaskAwaiter.OutputWaitEtwEvents.AnonymousMethod__0() Line 301
mscorlib.dll!System.Runtime.CompilerServices.AsyncMethodBuilderCore.ContinuationWrapper.Invoke() Line 1085
mscorlib.dll!System.Threading.Tasks.SynchronizationContextAwaitTaskContinuation.GetActionLogDelegate.AnonymousMethod__3() Line 470
mscorlib.dll!System.Threading.Tasks.SynchronizationContextAwaitTaskContinuation..cctor.AnonymousMethod__6(object state) Line 393
WindowsBase.dll!System.Windows.Threading.ExceptionWrapper.InternalRealCall(System.Delegate callback, object args, int numArgs) Line 118 Unknown
WindowsBase.dll!MS.Internal.Threading.ExceptionFilterHelper.TryCatchWhen(object source, System.Delegate method, object args, int numArgs, System.Delegate catchHandler) Line 41 Unknown
WindowsBase.dll!System.Windows.Threading.DispatcherOperation.InvokeImpl() Line 583 Unknown
WindowsBase.dll!System.Windows.Threading.DispatcherOperation.InvokeInSecurityContext(object state) Line 528 Unknown
mscorlib.dll!System.Threading.ExecutionContext.RunInternal(System.Threading.ExecutionContext executionContext, System.Threading.ContextCallback callback, object state, bool preserveSyncCtx) Line 581
mscorlib.dll!System.Threading.ExecutionContext.Run(System.Threading.ExecutionContext executionContext, System.Threading.ContextCallback callback, object state, bool preserveSyncCtx) Line 531
mscorlib.dll!System.Threading.ExecutionContext.Run(System.Threading.ExecutionContext executionContext, System.Threading.ContextCallback callback, object state) Line 520
WindowsBase.dll!System.Windows.Threading.DispatcherOperation.Invoke() Line 441 Unknown
WindowsBase.dll!System.Windows.Threading.Dispatcher.ProcessQueue() Line 2227 Unknown
WindowsBase.dll!System.Windows.Threading.Dispatcher.WndProcHook(System.IntPtr hwnd, int msg, System.IntPtr wParam, System.IntPtr lParam, ref bool handled) Line 2480 Unknown
WindowsBase.dll!MS.Win32.HwndWrapper.WndProc(System.IntPtr hwnd, int msg, System.IntPtr wParam, System.IntPtr lParam, ref bool handled) Line 345 Unknown
WindowsBase.dll!MS.Win32.HwndSubclass.DispatcherCallbackOperation(object o) Line 494 Unknown WindowsBase.dll!System.Windows.Threading.ExceptionWrapper.InternalRealCall(System.Delegate callback, object args, int numArgs) Line 111 Unknown WindowsBase.dll!MS.Internal.Threading.ExceptionFilterHelper.TryCatchWhen(object source, System.Delegate method, object args, int numArgs, System.Delegate catchHandler) Line 41 Unknown
WindowsBase.dll!System.Windows.Threading.Dispatcher.LegacyInvokeImpl(System.Windows.Threading.DispatcherPriority priority, System.TimeSpan timeout, System.Delegate method, object args, int numArgs) Line 1447 Unknown WindowsBase.dll!MS.Win32.HwndSubclass.SubclassWndProc(System.IntPtr hwnd, int msg, System.IntPtr wParam, System.IntPtr lParam) Line 398 Unknown
[Native to Managed Transition]
[Managed to Native Transition]
WindowsBase.dll!System.Windows.Threading.Dispatcher.PushFrameImpl(System.Windows.Threading.DispatcherFrame frame) Line 2281 Unknown
WindowsBase.dll!System.Windows.Threading.Dispatcher.PushFrame(System.Windows.Threading.DispatcherFrame frame) Line 369 Unknown
WindowsBase.dll!System.Windows.Threading.Dispatcher.Run() Line 328 Unknown
PresentationFramework.dll!System.Windows.Application.RunDispatcher(object ignore) Line 2745
PresentationFramework.dll!System.Windows.Application.RunInternal(System.Windows.Window window) Line 1841 PresentationFramework.dll!System.Windows.Application.Run(System.Windows.Window window) Line 261 PresentationFramework.dll!System.Windows.Application.Run() Line 222 UI.exe!UI.App.Main() [Native to Managed Transition]
mscorlib.dll!System.AppDomain.ExecuteAssembly(string assemblyFile, System.Security.Policy.Evidence assemblySecurity, string[] args) Line 2031
Microsoft.VisualStudio.HostingProcess.Utilities.dll!Microsoft.VisualStudio.HostingProcess.HostProc.RunUsersAssembly() Unknown mscorlib.dll!System.Threading.ThreadHelper.ThreadStart_Context(object state) Line 74
mscorlib.dll!System.Threading.ExecutionContext.RunInternal(System.Threading.ExecutionContext executionContext, System.Threading.ContextCallback callback, object state, bool preserveSyncCtx) Line 581
mscorlib.dll!System.Threading.ExecutionContext.Run(System.Threading.ExecutionContext executionContext, System.Threading.ContextCallback callback, object state, bool preserveSyncCtx) Line 531
mscorlib.dll!System.Threading.ExecutionContext.Run(System.Threading.ExecutionContext executionContext, System.Threading.ContextCallback callback, object state) Line 520
mscorlib.dll!System.Threading.ThreadHelper.ThreadStart() Line 111
[Async Call]
UI.exe!UI.Commands.AsyncCommandFactory.Create(System.Threading.CancellationToken token) Line 27
[Async Call]
UI.exe!UI.NotifyTaskCompletion.WatchTaskAsync(System.Threading.Tasks.Task task) Line 66
[Async Call]
UI.exe!UI.Commands.AsyncCommand.ExecuteAsync(object parameter) Line 55
[Async Call]
UI.exe!UI.Commands.AsyncCommandBase.Execute(object parameter) Line 15
- 下一个中断具有相同的异常并且与之前的堆栈跟踪几乎相同(不同之处仅在于最后调用的 4 个方法中的第一个)。
Call stack:
mscorlib.dll!System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(System.Threading.Tasks.Task task) Line 180
mscorlib.dll!System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(System.Threading.Tasks.Task task) Line 170
mscorlib.dll!System.Runtime.CompilerServices.TaskAwaiter.GetResult() Line 125
UI.exe!UI.Commands.AsyncCommandFactory.Create(System.Threading.CancellationToken token) Line 27
[Resuming Async Method]
...
- 下一个又是方法不同而已
Call stack:
mscorlib.dll!System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(System.Threading.Tasks.Task task) Line 180
mscorlib.dll!System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(System.Threading.Tasks.Task task) Line 170
mscorlib.dll!System.Runtime.CompilerServices.TaskAwaiter.GetResult() Line 125
UI.exe!UI.NotifyTaskCompletion.WatchTaskAsync(System.Threading.Tasks.Task task) Line 66
[Resuming Async Method]
...
- 在之前的中断之后,没有再引发异常并且 Task.IsFaulted 设置为 true。现在 UI 使用此绑定成功显示异常消息:
<Label Content="{Binding ProcessCurrentStepCommand.Execution.ErrorMessage}" Visibility="{Binding ProcessCurrentStepCommand.Execution.IsFaulted, Converter={StaticResource BooleanToVisibilityConverter}}" />
最终编辑。
要了解问题的背景和接受的答案,您需要查看这些文章:
I don’t want to propagate exceptions directly back to the main UI loop; I want to capture any exceptions and set properties so that the error handling is done via data binding.
那样的话,你真正需要的是一个synchronous命令,它只是starts异步操作,这里表示异步操作使用 NotifyTaskCompletion
(或您编写的某种类似类型)。像这样分解操作(分为同步 "start" 和异步数据绑定)比尝试将所有操作都集中在一起更容易(这也是可能的 - 只是代码不那么短或可重用):
// Represents the execution of the current step.
NotifyTaskCompletion ProcessCurrentStepCommandExecution
{
get { return _processCurrentStepCommandExecution; }
set { _processCurrentStepCommandExecution = value; PropertyChanged(); }
}
...
var cancellationToken = ...; // Wherever you get this from.
ProcessCurrentStepCommand = new DelegateCommand(() =>
{
ProcessCurrentStepCommandExecution = new NotifyTaskCompletion(async () =>
{
await Task.Run(() => CurrentStep.Process(cancellationToken));
// I'm assuming here you only want to move to the next step if there are no errors.
// Otherwise, this should be in a finally block.
CurrentStep = CurrentStep.NextStepViewModel;
});
});
编辑:
我相信您可能 运行 陷入了那篇文章的示例代码中的错误(在 MSDNMag 决定删除所有代码之前,评论中曾经更新过代码,我正在努力获取代码示例已更新,这是一个令人惊讶的漫长过程)。如果任务同步完成(异常或成功),则会出现错误;在这种情况下,NotifyTaskCompletion<T>.TaskCompleted
将是 null
。
要解决此问题,请将 NotifyTaskCompletion<T>
的构造函数更改为:
{
Task = task;
if (!task.IsCompleted)
TaskCompletion = WatchTaskAsync(task);
}
对此:
{
Task = task;
TaskCompletion = WatchTaskAsync(task);
}