WPF调用NetworkAdapter.GetConnectedProfileAsync遇线程错误求助
WPF中使用WinRT WiFi API触发跨线程错误的解决方法
问题描述
开发WPF应用时,借助WinRT库实现WiFi管理功能,需要获取当前连接网络的配置文件。代码逻辑无明显问题,但触发了线程错误。已确认代码运行在线程1,且是应用中唯一调用该类API的代码,不清楚该API的线程要求。
错误信息
The application called an interface that was marshalled for a different thread. (0x8001010E (RPC_E_WRONG_THREAD))
相关代码
var access = await WiFiAdapter.RequestAccessAsync(); if (access != WiFiAccessStatus.Allowed) { Networks = new List<WiFiAvailableNetwork>(); return; } var adapters = await WiFiAdapter.FindAllAdaptersAsync(); if (!adapters.Any()) return; Adapter = adapters.First(); await Adapter.ScanAsync(); Networks = Adapter.NetworkReport.AvailableNetworks; IReadOnlyList<ConnectionProfile> profiles = Array.Empty<ConnectionProfile>(); Application.Current.Dispatcher.Invoke(() => profiles = NetworkInformation.GetConnectionProfiles()); ConnectionProfiles = profiles; ConnectionProfile profile = default; try { profile = await Adapter.NetworkAdapter.GetConnectedProfileAsync(); } // <= 此处报错 catch (Exception ex) { Log.Exception(ex); }
已尝试的无效写法
await Application.Current.Dispatcher.Invoke(async () => profile = await Adapter.NetworkAdapter.GetConnectedProfileAsync()); await Application.Current.Dispatcher.InvokeAsync(async () => profile = await Adapter.NetworkAdapter.GetConnectedProfileAsync());
解决思路与代码修正
WinRT API具备线程亲和性,即创建WinRT对象的线程必须与访问该对象的线程保持一致。你之前的代码中,Adapter对象是在await后的后台线程上下文获取的,后续在UI线程访问它的NetworkAdapter属性时,就会触发跨线程调用错误。
正确的做法是将所有WinRT相关的API调用逻辑封装到同一个线程上下文中,避免跨线程访问WinRT对象:
修正后的代码
// 将整个WinRT操作逻辑放到UI线程调度中执行 await Application.Current.Dispatcher.InvokeAsync(async () => { var access = await WiFiAdapter.RequestAccessAsync(); if (access != WiFiAccessStatus.Allowed) { Networks = new List<WiFiAvailableNetwork>(); return; } var adapters = await WiFiAdapter.FindAllAdaptersAsync(); if (!adapters.Any()) return; Adapter = adapters.First(); await Adapter.ScanAsync(); Networks = Adapter.NetworkReport.AvailableNetworks; // 无需额外调度,直接在当前上下文调用NetworkInformation API ConnectionProfiles = NetworkInformation.GetConnectionProfiles(); try { var profile = await Adapter.NetworkAdapter.GetConnectedProfileAsync(); // 在这里处理获取到的连接配置文件 } catch (Exception ex) { Log.Exception(ex); } });
替代方案(.NET 6+ 推荐)
如果你的应用基于.NET 6及以上版本,可使用WinRT原生的DispatcherQueue进行线程调度,适配性更好:
var dispatcherQueue = DispatcherQueue.GetForCurrentThread(); await dispatcherQueue.TryEnqueue(async () => { // 所有WinRT API调用逻辑都放在这里 var access = await WiFiAdapter.RequestAccessAsync(); // ... 后续逻辑同上 });
核心原因总结
WinRT对象绑定到创建它的线程上下文,无法跨线程直接访问。你之前的错误在于拆分了WinRT对象的创建与属性访问操作到不同线程,将整个流程统一到同一个调度上下文即可解决问题。
内容的提问来源于stack exchange,提问作者Travis
相关产品推荐
相关产品推荐

