为什么Xamarin Forms Shell传递的参数无法被接收端ViewModel正确接收
问题原因&修复方案
- 接收端ViewModel构造执行优先级高于QueryProperty赋值
构造函数运行时QueryProperty还未完成参数传递,你在构造中初始化Command时捕获的sxCaseId是默认空值,就算后续参数赋值成功,Command里用的还是旧值,不会触发正确的加载逻辑。 - SxCaseId赋值后未触发数据加载
现有代码中SxCaseId的set方法仅给字段赋值,没有调用数据加载逻辑,参数传过来也不会拉取接口数据。 - XAML绑定语法错误
RefreshView的IsRefreshing属性绑定规则错误,你写的{Binding RefreshSxCaseStaffJoinCommand,IsBusy, Mode=TwoWay}不符合绑定规范,应该单独绑定IsBusy属性,刷新命令绑定到RefreshView的Command属性。 - 数据加载完成后未通知UI更新
LoadSxCaseStaffJoins方法直接给SxCaseStaffJoins赋值,没有调用SetProperty触发属性变更通知,UI收不到更新自然显示空白。 - Task.Delay未加await
多处Task.Delay(500)没有加await,延迟逻辑完全不生效,还会导致异步任务脱离上下文。
修复后代码
接收端ViewModel
[QueryProperty(nameof(SxCaseId), nameof(SxCaseId))] public class StaffViewModel : ViewModelBase { private ISxCaseDataService _sxCaseDataService; private IStaffDataService _staffDataService; private SxCaseStaffJoin _selectedSxCaseStaffJoin; private SxCaseStaffJoin _sxCaseStaffJoin; private int _sxCaseId; private ObservableCollection<SxCaseStaffJoin> _sxCaseStaffJoins; public ObservableCollection<SxCaseStaffJoin> SxCaseStaffJoins { get => _sxCaseStaffJoins; set => SetProperty(ref _sxCaseStaffJoins, value); } public ICommand LoadSxCaseStaffJoinCommand { get; } public ICommand RefreshSxCaseStaffJoinCommand { get; } public StaffViewModel(IConnectionService connectionService, IDialogService dialogService, ISxCaseDataService sxCaseDataService, IStaffDataService staffDataService) : base(connectionService, dialogService) { _sxCaseDataService = sxCaseDataService; _staffDataService = staffDataService; SxCaseStaffJoin = _sxCaseStaffJoin; SxCaseStaffJoins = new ObservableCollection<SxCaseStaffJoin>(); Title = "Staff"; // 直接取当前属性值,不要捕获构造时的变量 LoadSxCaseStaffJoinCommand = new Command(async () => await ExecuteLoadSxCaseStaffJoinsCommand()); RefreshSxCaseStaffJoinCommand = new Command(async () => await LoadSxCaseStaffJoins()); } public SxCaseStaffJoin SxCaseStaffJoin { get => _sxCaseStaffJoin; set => SetProperty(ref _sxCaseStaffJoin, value); } // 改成int类型,Shell会自动做类型转换 public int SxCaseId { get => _sxCaseId; set { SetProperty(ref _sxCaseId, value); // 赋值完成后自动触发数据加载 _ = LoadSxCaseStaffJoins(); } } private async Task ExecuteLoadSxCaseStaffJoinsCommand() { IsBusy = true; try { SxCaseStaffJoins.Clear(); var sxCaseStaffJoins = await _staffDataService.GetSxCaseStaffJoinForSxCase(SxCaseId); foreach (var sxCaseStaffJoin in sxCaseStaffJoins) { SxCaseStaffJoins.Add(sxCaseStaffJoin); } } catch (Exception ex) { Debug.WriteLine(ex); } finally { IsBusy = false; } } private async Task LoadSxCaseStaffJoins() { IsBusy = true; await Task.Delay(500); SxCaseStaffJoins = new ObservableCollection<SxCaseStaffJoin>( await _staffDataService.GetSxCaseStaffJoinForSxCase(SxCaseId)); IsBusy = false; } }
页面XAML
<?xml version="1.0" encoding="utf-8" ?> <ContentPage xmlns="http://xamarin.com/schemas/2014/forms" xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml" xmlns:utility="clr-namespace:QiX.Utility;assembly=QiX" xmlns:iOsSpecific="clr-namespace:Xamarin.Forms.PlatformConfiguration.iOSSpecific;assembly=Xamarin.Forms.Core" xmlns:viewModels="clr-namespace:QiX.ViewModels;assembly=QiX" x:Class="QiX.Views.StaffView" x:DataType="viewModels:StaffViewModel" Title="{Binding Title}" utility:ViewModelLocator.AutoWireViewModel="True" iOsSpecific:Page.UseSafeArea="True" x:Name="StaffPage"> <ContentPage.Content> <RefreshView IsRefreshing="{Binding IsBusy, Mode=TwoWay}" Command="{Binding RefreshSxCaseStaffJoinCommand}"> <ScrollView> <CollectionView ItemsSource="{Binding SxCaseStaffJoins}"> <CollectionView.ItemTemplate> <DataTemplate> <TextCell Text="{Binding SxCaseId}"/> </DataTemplate> </CollectionView.ItemTemplate> </CollectionView> </ScrollView> </RefreshView> </ContentPage.Content> </ContentPage>
额外检查项
- 确认在AppShell.xaml.cs中已经注册了页面路由:
Routing.RegisterRoute(nameof(StaffView), typeof(StaffView)); - 发送端可以加判空避免传空值:
async void LoadStaff(SxCase sxCase) { if(sxCase == null) return; await Task.Delay(500); await Shell.Current.GoToAsync( $"{nameof(StaffView)}?{nameof(StaffViewModel.SxCaseId)}={sxCase.SxCaseId}"); }
内容的提问来源于stack exchange,提问作者Brady
相关产品推荐
相关产品推荐

