困惑于Async、Await和Task,求WPF中NetworkPlaces异步非阻塞实现
解决方案:在后台线程执行同步网络扫描以避免UI阻塞
你的核心问题是同步的网络扫描逻辑直接在UI线程执行,虽然用了async/await,但NetworkPlaces方法本身没有真正的异步操作,只是返回一个已完成的Task,所以UI线程依然会被阻塞。下面是可运行的修改方案:
完整修改代码
public RelayCommand ScanForDevicesCMD { get; private set; } // 新增扫描状态标志,防止重复触发 private bool _isScanning; public bool IsScanning { get => _isScanning; set { _isScanning = value; // 通知UI和命令状态变化(假设实现了INotifyPropertyChanged) OnPropertyChanged(nameof(IsScanning)); ScanForDevicesCMD.RaiseCanExecuteChanged(); } } public MainVM() { ScanForDevicesCMD = new RelayCommand(ScanForDevices, CanScanForDevices); } // 命令执行方法,保持async void(因为是UI命令触发) public async void ScanForDevices(object obj) { Debug.WriteLine("SCAN STARTED"); IsScanning = true; try { // 将同步扫描逻辑包装到Task.Run,放到后台线程执行 await Task.Run(() => NetworkPlaces()); } finally { IsScanning = false; Debug.WriteLine("SCAN STOPPED"); } } // 同步扫描方法,专注于业务逻辑 private void NetworkPlaces() { ShellNetworkComputers shellNetworkComputers = new ShellNetworkComputers(); foreach (string snc in shellNetworkComputers) { Debug.WriteLine(snc); // 如果需要更新UI(比如绑定设备列表),需要切换回UI线程 // Application.Current.Dispatcher.Invoke(() => { /* 更新UI逻辑 */ }); } } // 命令可用状态判断 private bool CanScanForDevices(object obj) { return !IsScanning; } // 假设你已经实现了INotifyPropertyChanged接口的OnPropertyChanged方法 protected virtual void OnPropertyChanged(string propertyName) { PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName)); } public event PropertyChangedEventHandler PropertyChanged;
关键修改点说明
用Task.Run包装同步逻辑:
把耗时的NetworkPlaces同步操作放到Task.Run中,让它在ThreadPool后台线程执行,UI线程可以继续响应用户操作。添加扫描状态控制:
新增IsScanning属性,配合CanScanForDevices方法,防止用户重复点击扫描按钮,避免并发扫描的问题。正确处理异步流程:
使用try/finally确保扫描结束后无论成功失败都能重置IsScanning状态,保证命令状态正确。UI更新注意事项:
如果后续需要把扫描到的设备绑定到UI控件(比如ListView),必须通过Dispatcher.Invoke或者Dispatcher.BeginInvoke切换回UI线程执行更新逻辑,否则会抛出跨线程访问UI的异常。
内容的提问来源于stack exchange,提问作者stigzler
相关产品推荐
相关产品推荐

