You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

UWP CommunityToolkit Messenger异步处理报InvalidOperationException解决方案

问题根因

WeakReferenceMessenger的请求消息存在硬性约束:所有注册的消息处理器必须在同步执行阶段调用Reply()方法设置返回值。
你当前给消息处理委托加了async/await后,执行到await continueCallbackAnsweringDialog.ShowAsync()时,委托会将控制权交回给Messenger的Send方法,Messenger遍历完所有处理器后发现没有任何处理器设置返回值,就会直接抛出InvalidOperationException。等弹窗交互完成、你再调用message.Reply()时,消息对象的处理生命周期已经结束,自然无法正常返回结果。
你测试移除async/await后代码可正常运行,本质就是刚好满足了Messenger「同步Reply」的要求,但这种写法无法等待异步弹窗的交互结果,和业务需求存在冲突。

正确实现方案

不要在消息处理器内部等待异步弹窗完成,而是同步将「等待用户交互的Task」作为Reply值返回,让ViewModel侧自行等待最终结果,不要让Messenger阻塞等待异步逻辑。

调整消息注册端(Dialer.xaml.cs)逻辑

移除消息处理委托的async/await关键字,弹窗的异步等待逻辑收敛到TaskCompletionSource中,同步返回待完成的Task即可:

WeakReferenceMessenger.Default.Register<ContinueCallbackAnsweringRequestMessage>(this, (r, message) =>
{
    var continueCallbackAnsweringDialog = new MessageDialog("آیا مایل به ادامه پاسخ‌دهی به تماس‌های درخواستی هستید؟");
    TaskCompletionSource<CancellationToken> tcs = new TaskCompletionSource<CancellationToken>(TaskCreationOptions.RunContinuationsAsynchronously);
    
    continueCallbackAnsweringDialog.Commands.Add(new UICommand(
        "بلی",
        new UICommandInvokedHandler((IUICommand command) =>
        {
            tcs.SetResult(new CancellationToken(false));
        })));
    continueCallbackAnsweringDialog.Commands.Add(new UICommand(
        "خیر",
        new UICommandInvokedHandler((IUICommand command) =>
        {
            tcs.SetResult(new CancellationToken(true));
        })));
    continueCallbackAnsweringDialog.DefaultCommandIndex = 0;
    continueCallbackAnsweringDialog.CancelCommandIndex = 1;

    // 触发弹窗显示,不阻塞当前消息处理流程
    _ = continueCallbackAnsweringDialog.ShowAsync();
    // 同步Reply返回待完成的Task,满足Messenger的同步返回要求
    message.Reply(tcs.Task);
});

说明:_ = continueCallbackAnsweringDialog.ShowAsync(); 是用弃元丢弃异步操作的编译器警告,我们不需要在消息处理器中等待弹窗完成,用户点击按钮时会自动给TaskCompletionSource设置结果。

确认消息类定义兼容

你的ContinueCallbackAnsweringRequestMessage需要支持返回Task<CancellationToken>类型,对应定义参考如下:

public class ContinueCallbackAnsweringRequestMessage : RequestMessage<Task<CancellationToken>>
{
}

调整后ViewModel侧的CallbackClick逻辑不需要做任何修改,await拿到的结果就是用户弹窗选择后的CancellationToken,完全符合原有业务预期。

额外注意事项
  • 记得在Dialer.xaml.cs的NavigatedFrom生命周期回调中注销对应消息,避免内存泄漏:
    WeakReferenceMessenger.Default.Unregister<ContinueCallbackAnsweringRequestMessage>(this);
    
  • 不要在WeakReferenceMessenger的消息处理委托中使用async void写法,除了会导致Reply时机错误触发异常,async void未捕获的异常会直接导致应用崩溃。

内容的提问来源于stack exchange,提问作者sorosh_sabz

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.28 01:15:34