WPF/C#异步搜索实现问题咨询:UWP包搜索系统报错求修复方案
问题修复与优化方案
错误原因
- 取消逻辑时机错误:你将取消检查放在了UI更新操作之后,就算任务被取消,耗时的搜索、UI绑定操作已经执行完成,取消机制完全没有生效
- 取消触发场景不全:PreviewTextInput仅能捕获键盘字符输入,无法覆盖删除、粘贴、输入法选字等触发文本变更的场景,大量场景下旧任务无法正常取消
- 耗时操作阻塞UI线程:包遍历、筛选逻辑直接放在Dispatcher(UI线程)中执行,输入频繁时会直接导致UI卡顿,也是你遇到报错的核心诱因
修复方案
直接替换原有逻辑即可,不需要再监听PreviewTextInput事件:
// 类成员变量,全局持有取消令牌源 private CancellationTokenSource _searchTokenSource; private async void OnSearchBox_TextChanged(object sender, TextChangedEventArgs e) { // 先取消之前还在运行的搜索任务 _searchTokenSource?.Cancel(); _searchTokenSource?.Dispose(); var currentKeyword = searchBox.Text.Trim().ToLower(); if (string.IsNullOrEmpty(currentKeyword)) { appsListBox.ItemsSource = null; return; } _searchTokenSource = new CancellationTokenSource(); var token = _searchTokenSource.Token; try { // 后台线程跑搜索逻辑,不卡UI var matchedPackages = await Task.Run(() => { // 每次迭代都检查是否取消,避免做无用功 return packageManager.FindPackagesForUser("") .Where(p => { token.ThrowIfCancellationRequested(); return p.DisplayName.ToLower().Contains(currentKeyword); }) .ToList(); }, token); // 只有没被取消的情况才更新UI if (!token.IsCancellationRequested) { appsListBox.ItemsSource = matchedPackages; } } catch (OperationCanceledException) { // 搜索被取消直接忽略即可 System.Diagnostics.Debug.WriteLine("旧搜索任务已取消"); } }
更优实现建议
增加防抖逻辑,用户输入过程中不立刻触发搜索,等待输入暂停300ms后再执行搜索,能进一步降低性能消耗:
// 新增类成员变量,存储防抖延迟任务 private Task _debounceTask; private async void OnSearchBox_TextChanged(object sender, TextChangedEventArgs e) { _searchTokenSource?.Cancel(); _searchTokenSource?.Dispose(); var currentKeyword = searchBox.Text.Trim().ToLower(); if (string.IsNullOrEmpty(currentKeyword)) { appsListBox.ItemsSource = null; return; } _searchTokenSource = new CancellationTokenSource(); var token = _searchTokenSource.Token; // 防抖等待,新输入触发时之前的等待任务会被取消 try { await Task.Delay(300, token); } catch (OperationCanceledException) { return; } try { var matchedPackages = await Task.Run(() => { return packageManager.FindPackagesForUser("") .Where(p => { token.ThrowIfCancellationRequested(); return p.DisplayName.ToLower().Contains(currentKeyword); }) .ToList(); }, token); if (!token.IsCancellationRequested) { appsListBox.ItemsSource = matchedPackages; } } catch (OperationCanceledException) { System.Diagnostics.Debug.WriteLine("旧搜索任务已取消"); } }
内容的提问来源于stack exchange,提问作者ImMike-SB
相关产品推荐
相关产品推荐

