ListView中线程安全调用FindItemWithText的最优实现方案求教
针对你用FindItemWithText实现跨线程搜索ListView的场景,我整理几个更优的实现思路,帮你简化代码同时提升性能:
首先先补全你给出的初步实现代码(方便对照参考):
string SearchLocal(string findstr) { string item = findstr; if (lvContactsLocal.InvokeRequired) { lvContactsLocal.Invoke((MethodInvoker)delegate () { var foundItem = lvContactsLocal.FindItemWithText(findstr, true, 0); if (foundItem != null) { item = foundItem.Text; // 可能包含选中、滚动到项等UI操作 } }); } else { var foundItem = lvContactsLocal.FindItemWithText(findstr, true, 0); if (foundItem != null) { item = foundItem.Text; } } return item; }
优化思路1:封装通用线程安全扩展方法
把跨线程调用的逻辑封装成扩展方法,避免重复编写Invoke判断代码,后续其他ListView也能直接复用:
public static class ListViewExtensions { // 线程安全的FindItemWithText封装 public static ListViewItem SafeFindItemWithText(this ListView listView, string text, bool includeSubItemsInSearch, int startIndex) { if (listView.InvokeRequired) { // 用Func委托传递参数并返回结果,替代MethodInvoker return (ListViewItem)listView.Invoke( new Func<string, bool, int, ListViewItem>(SafeFindItemWithText), text, includeSubItemsInSearch, startIndex); } return listView.FindItemWithText(text, includeSubItemsInSearch, startIndex); } }
之后你的搜索方法可以简化成:
string SearchLocal(string findstr) { var foundItem = lvContactsLocal.SafeFindItemWithText(findstr, true, 0); return foundItem?.Text ?? findstr; }
优化思路2:异步搜索避免阻塞UI
如果你的ListView数据量较大,直接在UI线程调用FindItemWithText可能会导致界面卡顿。可以把搜索逻辑放到后台线程,仅在需要更新UI时回到主线程:
async Task<string> SearchLocalAsync(string findstr) { // 先把ListView的项数据复制到后台可访问的集合(避免跨线程直接操作控件) List<ListViewItem> itemsCopy = null; await lvContactsLocal.InvokeAsync(() => { itemsCopy = lvContactsLocal.Items.Cast<ListViewItem>().ToList(); }); // 在后台线程执行搜索逻辑(可自定义匹配规则) var foundItem = await Task.Run(() => { return itemsCopy.FirstOrDefault(item => item.Text.Contains(findstr) || item.SubItems.Cast<ListViewItem.ListViewSubItem>().Any(sub => sub.Text.Contains(findstr))); }); // 回到UI线程执行选中、滚动等操作 if (foundItem != null) { await lvContactsLocal.InvokeAsync(() => { lvContactsLocal.SelectedItems.Clear(); foundItem.Selected = true; lvContactsLocal.EnsureVisible(foundItem.Index); }); return foundItem.Text; } return findstr; }
优化思路3:提前缓存搜索数据(适合高频搜索场景)
如果需要频繁执行搜索操作,可以提前把ListView的文本数据缓存到线程安全的集合中,避免每次搜索都从控件读取数据:
// 定义缓存集合,存储所有项的文本(包含子项) private List<string> _searchCache; // 初始化缓存(比如在ListView加载完成后调用) private void InitializeSearchCache() { _searchCache = lvContactsLocal.Items.Cast<ListViewItem>() .Select(item => $"{item.Text}|{string.Join("|", item.SubItems.Cast<ListViewItem.ListViewSubItem>().Select(sub => sub.Text))}") .ToList(); } // 搜索方法 string SearchLocal(string findstr) { var matchedText = _searchCache.FirstOrDefault(text => text.Contains(findstr)); if (matchedText != null) { // 找到匹配内容后,回到UI线程定位到对应项 lvContactsLocal.Invoke(() => { var foundItem = lvContactsLocal.FindItemWithText(matchedText.Split('|')[0], true, 0); if (foundItem != null) { foundItem.Selected = true; lvContactsLocal.EnsureVisible(foundItem.Index); } }); return matchedText.Split('|')[0]; } return findstr; }
注意:当ListView的项发生添加、删除、修改时,需要同步更新_searchCache,保证缓存数据与控件一致。
内容的提问来源于stack exchange,提问作者user9616781
相关产品推荐
相关产品推荐

