Xamarin.Forms CollectionView选中项progress属性UI更新不一致问题
问题原因
- 代码内混用大小写的
currentEntry和CurrentEntry变量,若二者指向不同实例,修改CurrentEntry的属性不会同步到列表绑定的实例,自然不会触发UI更新。 - 多余的
Task.Run包裹异步逻辑导致线程上下文切换,增加了属性更新通知的线程同步风险,部分情况下UI线程无法正确接收INotifyPropertyChanged的触发事件。 - 属性更新未显式调度到UI线程执行,后台线程触发的属性变更在部分场景下会丢失通知。
修复方案
- 移除多余的
Task.Run包裹,异步IO请求本身无需额外开启后台线程。 - 统一所有地方使用大写的
CurrentEntry变量,确保修改的就是选中项绑定的实例。 - 显式将progress属性的更新逻辑调度到UI线程执行。
修复后的业务逻辑代码
async Task Info() { IsBusy = true; try { if (CurrentEntry.progress < CurrentEntry.media.Episodes) { string token = Preferences.Get("token", "default_value"); var anilistGraphQlHttpClient = new GraphQLHttpClient("https://graphql.anilist.co", new NewtonsoftJsonSerializer()); anilistGraphQlHttpClient.HttpClient.DefaultRequestHeaders.Add("Authorization", "Bearer " + token); var IncreaseProgressEntry = new GraphQLRequest { Query = @"mutation IncreaseProgress($id: Int, $progress: Int) { SaveMediaListEntry(id: $id, progress: $progress) { id progress status } } ", OperationName = "IncreaseProgress", Variables = new { id = CurrentEntry.id, progress = CurrentEntry.progress + 1 } }; await anilistGraphQlHttpClient.SendQueryAsync<Data>(IncreaseProgressEntry); // 显式在UI线程更新属性 MainThread.BeginInvokeOnMainThread(() => { CurrentEntry.progress += 1; }); Console.WriteLine("success"); } } catch (HttpRequestException httpRequestException) { Console.WriteLine(httpRequestException); MainThread.BeginInvokeOnMainThread(() => { DependencyService.Get<Toast>().Show("无网络连接"); }); } catch (GraphQLHttpRequestException e) { Console.WriteLine(e); Preferences.Set("token", "default_value"); await Shell.Current.GoToAsync("//LandingPage"); MainThread.BeginInvokeOnMainThread(() => { DependencyService.Get<Toast>().Show("令牌已过期或被撤销"); }); } catch (Exception e) { Console.WriteLine(e); MainThread.BeginInvokeOnMainThread(() => { DependencyService.Get<Toast>().Show("发生未知错误"); }); } finally { IsBusy = false; } }
额外检查项
- 确认绑定到CollectionView的
AnimeGroupObservable内存储的ListEntry实例,和CurrentEntry选中的是同一个引用,刷新列表时不要直接替换整个列表实例,优先更新现有实例的属性。 - 可在
ListEntry的progress属性set方法内加断点,确认每次点击+号都会触发OnPropertyChanged调用,若未触发则说明修改的不是同一个实例。
内容的提问来源于stack exchange,提问作者ziomek64
相关产品推荐
相关产品推荐

