.NET MAUI中RefreshView绑定IsBusy自动触发RefreshCommand问题
这是RefreshView控件的预期设计行为,并非使用疏漏。
在.NET MAUI(含其前身Xamarin.Forms)的RefreshView实现逻辑中,只要你同时绑定了IsRefreshing属性和Command属性,无论IsRefreshing变为true的触发源是用户下拉操作,还是代码手动赋值,控件都会自动执行绑定的刷新命令。
你的Init方法首行执行IsBusy = true时,RefreshView检测到绑定的IsRefreshing(即你的IsBusy属性)从false切换为true,就会自动触发RefreshDataCommand执行,最终导致GetData被先后调用两次。
最稳妥的实现方式是拆分通用加载状态和下拉刷新状态,不要把页面全局用的IsBusy直接绑定给RefreshView,避免非下拉场景的状态变更意外触发刷新命令。
- 在ViewModel中单独定义仅用于标识下拉刷新状态的属性,和全局加载状态
IsBusy隔离 - 仅在下拉刷新逻辑中修改这个专属状态属性,初始化加载缓存时只操作
IsBusy,不触发刷新状态变更
修正后的ViewModel代码示例:
public partial MyViewModel : BaseViewModel { ObservableCollection<MyModel> MyData { get; } = new(); // 专属RefreshView的刷新状态,不与全局加载状态混用 [ObservableProperty] private bool isRefreshing; [RelayCommand] async Task RefreshData() { IsRefreshing = true; await GetData(true); IsRefreshing = false; } private async Task GetData(bool shouldGetFreshData) { // 原有API调用、缓存读取、集合赋值逻辑保持不变 } public async void Init() { IsBusy = true; await GetData(false); IsBusy = false; } }
对应XAML绑定修改如下:
<RefreshView IsRefreshing="{Binding IsRefreshing}" Command="{Binding RefreshDataCommand}"> <CollectionView> <!-- 原有CollectionView配置保持不变 --> </CollectionView> </RefreshView>
如果不想新增属性,也可以通过增加初始化标记位的方式临时拦截命令执行:在ViewModel中定义_isInitializing布尔标记,Init执行时先将标记设为true,RefreshData方法开头判断如果标记为true就直接返回,等Init逻辑执行完成后再把标记改回false。但这种方式边界处理成本更高,更推荐拆分状态的实现方式。
补充说明:
RefreshView.IsRefreshing不是单纯的可视化状态标识,控件设计这个双向绑定属性的初衷之一,就是允许开发者通过代码修改该属性值,主动触发刷新命令执行、控制刷新动画展示。
内容的提问来源于stack exchange,提问作者Sam

