C++/WinRT中OnNavigatingFrom方法如何调用异步非阻塞代码
你不需要通过.get()把异步调用转成同步阻塞执行,C++/WinRT提供了和C# async void 行为完全对等的「发后不理(fire-and-forget)」协程模式,完全适配这种框架固定签名为void的重写方法场景。
核心实现逻辑
Page::OnNavigatingFrom是XAML框架定义的重写方法,签名固定返回void,你不能把它的返回值改成IAsyncAction——框架不会识别、也不会等待自定义返回值的重写方法,强行改签名会导致重写失效。
正确的做法是把异步逻辑封装到返回winrt::fire_and_forget的协程函数中,在OnNavigatingFrom里直接调用这个协程即可,调用后会立刻返回,不会阻塞当前导航流程,和C#里写async void的行为完全一致。
代码示例
// OnNavigatingFrom 重写方法,保持原签名不变 void MyPage::OnNavigatingFrom(NavigatingCancelEventArgs const& e) { // 所有需要同步执行的导航判断逻辑放在这里 // 例如判断是否有未保存内容需要立刻拦截导航的逻辑,必须同步设置e.Cancel if (HasUnsynchronizedChangesThatMustBlockNav()) { e.Cancel(true); return; } // 直接调用发后不理的异步逻辑,不阻塞导航继续执行 RunAsyncNavCleanupWork(); } // 封装异步逻辑的发后不理协程 winrt::fire_and_forget MyPage::RunAsyncNavCleanupWork() { // 第一步必须持有当前页面对象的强引用,避免协程恢复时页面已被销毁导致this悬空崩溃 auto strongThis = get_strong(); // 切到后台线程执行耗时IO/计算逻辑,不阻塞UI co_await winrt::resume_background(); // 这里写你的非阻塞异步逻辑,比如持久化页面状态、释放后台占用的资源等 co_await SaveUserEditStateToLocalStorageAsync(); co_await ReleaseUnmanagedResourceHandlesAsync(); // 如果后续需要操作UI元素,必须切回UI线程执行 co_await winrt::resume_foreground(Dispatcher()); // 执行UI线程相关的收尾逻辑 UpdateLastNavigationTimestamp(); }
关键注意事项
- 和C#的
async void一样,fire_and_forget协程一旦启动就不会被OnNavigatingFrom等待,导航流程会正常推进,不要在协程的co_await之后修改NavigatingCancelEventArgs的Cancel属性——这时候OnNavigatingFrom早已执行完毕,修改参数不会产生任何效果。 - 如果你的业务逻辑需要等待异步结果才能决定是否取消导航,必须在同步阶段先将
e.Cancel设为true拦截本次导航,等异步逻辑执行完成、判断允许导航后,再手动调用Frame的导航方法触发新的导航,不能直接在OnNavigatingFrom里靠等待异步结果来拦截。 - 严禁在UI线程上对异步操作调用
.get(),这会直接造成死锁:UI线程等待异步操作完成,而异步操作完成后的回调默认需要回到UI线程执行,两者互相等待会直接导致应用卡死。
内容的提问来源于stack exchange,提问作者Thomas Flinkow
相关产品推荐
相关产品推荐

