.NET MAUI在AppShell中调用DisplayAlert触发TargetInvocation异常求助
.NET MAUI AppShell中SignalR回调调用DisplayAlert异常的解决办法
问题根源
SignalR的NewCallNotificationReceived回调运行在非UI线程,而DisplayAlert是依赖UI上下文的操作,直接调用会因线程上下文不匹配抛出TargetInvocation异常;Label显示能正常运行是因为部分控件更新会隐式处理线程同步,但弹窗类操作要求严格的UI线程上下文。
修复方案
修改代码,确保SignalR回调中的弹窗操作在UI线程执行,同时优化Hub连接的异步逻辑:
private readonly HubConnection _hubConnection; private string baseUrl = "https:/"; public AppShell() { InitializeComponent(); NavigationPage.SetHasBackButton(this, false); _hubConnection = new HubConnectionBuilder() .WithUrl($"{baseUrl}/notificationhub") .Build(); // 回调中强制切换到UI线程执行弹窗 _hubConnection.On<Notification>("NewCallNotificationReceived", async (notify) => { await MainThread.InvokeOnMainThreadAsync(async () => { await DisplayAlert("Title", notify.Message, "OK"); }); }); // 异步初始化Hub连接,避免冗余线程嵌套 _ = InitializeHubAsync(); } // 用async Task替代async void,避免异常丢失 private async Task InitializeHubAsync() { try { await _hubConnection.StartAsync(); } catch (Exception ex) { // 连接失败时也在UI线程提示 await MainThread.InvokeOnMainThreadAsync(async () => { await DisplayAlert("连接失败", $"错误信息: {ex.Message}", "确定"); }); } }
关键修改点
- 使用
MainThread.InvokeOnMainThreadAsync将弹窗操作强制切换到UI线程,这是.NET MAUI跨平台的推荐写法,比直接用Dispatcher更可靠。 - 移除了
async void的ShowPopup方法,改用async Task管理异步操作,避免异步异常无法被捕获的问题。 - 重构Hub连接启动逻辑,去掉冗余的
Task.Run嵌套Dispatcher写法,代码更简洁且符合异步规范。
内容的提问来源于stack exchange,提问作者Robert
相关产品推荐
相关产品推荐

