Xamarin Forms CollectionView搜索展示Azure Cosmos DB数据时出现重复问题
解决Xamarin Forms中CollectionView展示Cosmos DB数据时的重复问题
可能的原因及对应解决方案
1. 搜索事件并发触发导致重复加载
TextChanged事件会在用户输入的每一个字符变化时触发,如果前一次异步搜索请求还未完成,后一次请求又启动,就会导致多次向集合中添加数据,最终出现重复项。
解决方案:添加并发控制标识,避免重复发起请求:
// 类级别变量,标记当前是否正在执行搜索 private bool _isSearching; void OnSearchCommunity(System.Object sender, Xamarin.Forms.TextChangedEventArgs e) { var searchTerm = e.NewTextValue?.Trim() ?? string.Empty; // 如果正在搜索,直接返回,避免并发请求 if (_isSearching) return; Device.BeginInvokeOnMainThread(async () => { _isSearching = true; try { MyCommunityCollectionList.ItemSizingStrategy = ItemSizingStrategy.MeasureFirstItem; MyCommunityCollectionList.ItemsSource = await OnPersonSearch(searchTerm); } finally { // 无论请求成功或失败,都标记搜索结束 _isSearching = false; } }); }
2. 复用ObservableRangeCollection导致数据残留
当前使用类级别的datasource变量,虽然每次调用Clear()清空,但如果异步操作时序出现问题,或者集合引用未正确更新,可能导致旧数据残留。
解决方案:每次搜索都创建新的ObservableRangeCollection,避免复用旧集合:
// 移除类级别的datasource和CommunityUser变量,改为方法内局部声明 async Task<ObservableRangeCollection<MyCommunityModel>> OnPersonSearch(string MyFriendName) { // 每次搜索创建全新的集合实例 var datasource = new ObservableRangeCollection<MyCommunityModel>(); var UsersList = await UserManager.GetUserList(MyFriendName); foreach (var u in UsersList) { var CommunityUser = new MyCommunityModel(); CommunityUser.MyId = u.MyId; CommunityUser.Username = u.Username; // 修正:使用原用户对象的图片地址,而非未赋值的CommunityUser属性 var imageData = await AzureDatalakeBlob.GetFileAsync(AzureDatalakeBlob.ContainerType.leafwordsapp, u.UserImageBlobAdress); if (imageData != null) { CommunityUser.UserImage = ImageSource.FromStream(() => new MemoryStream(imageData)); } else { CommunityUser.UserImage = ImageSource.FromResource("LeafWords.MyImages.MySettings.person.png"); } datasource.Add(CommunityUser); } return datasource; }
3. Cosmos DB查询返回重复数据
如果Cosmos DB的查询本身返回了重复的用户数据,可以在获取结果后进行去重处理:
public async static Task<List<MyUser>> GetUserList(string MyFriendName) { MyFriendName = MyFriendName.ToLower(); List<MyUser> UsersList = new List<MyUser>(); // 替换字符串拼接,使用参数化查询避免SQL注入风险 string sql = $"SELECT TOP 25 * FROM {collectionId} u WHERE CONTAINS(LOWER(u.username), @friendName)"; QueryDefinition query = new QueryDefinition(sql) .WithParameter("@friendName", MyFriendName); using (FeedIterator<MyUser> iterator = container.GetItemQueryIterator<MyUser>( queryDefinition: query, requestOptions: new QueryRequestOptions() { MaxItemCount = -1, })) { while (iterator.HasMoreResults) { FeedResponse<MyUser> result = await iterator.ReadNextAsync(); UsersList.AddRange(result.Resource); } // 按用户唯一ID去重,确保结果集中无重复项 UsersList = UsersList.DistinctBy(u => u.MyId).ToList(); return UsersList; } }
内容的提问来源于stack exchange,提问作者hugo
相关产品推荐
相关产品推荐

