MVVM模式下跨页面传递ObservableCollection<Video>失败问题
MVVM模式下跨页面传递ObservableCollection
项目中MVVM模式在其他场景正常运行,但跨页面传递ObservableCollection<Video>时出现异常,具体情况如下:
发送端实现
声明并在构造函数中实例化集合:
[ObservableProperty] private ObservableCollection<Video> videoList; //... public Constructor() { VideoList = new ObservableCollection<Video>(); }
触发跳转传值的命令:
[RelayCommand] private async Task CreateCase() { if (0 == VideoList.Count) { await App.Current.MainPage.DisplayAlert("No video(s) selected", "You must have at least one video selected to add to your new Case.", "", "OK"); return; } Dictionary<string, object> param = new Dictionary<string, object> { { "VideoList", VideoList } }; await Shell.Current.GoToAsync($"//{nameof(CreateCasePage)}", param); }
已确认字典中成功存入包含3个选中对象的ObservableCollection<Video>。
接收端初始实现
使用QueryProperty特性,属性名称与发送端一致:
[QueryProperty("VideoList", "VideoList")] public partial class CreateCasePageViewModel : ObservableObject { [ObservableProperty] private ObservableCollection<Video> videoList; //... public Constructor() { VideoList = new ObservableCollection<Video>(); } }
无论是否在构造函数中实例化集合,接收端的VideoList始终为null。
尝试IQueryAttributable接口优化
发送端代码不变,接收端实现IQueryAttributable接口:
public partial class CreateCasePageViewModel : ObservableObject, IQueryAttributable { [ObservableProperty] private ObservableCollection<Video> videoList; public void ApplyQueryAttributes(IDictionary<string, object> query) { VideoList = query["VideoList"] as ObservableCollection<Video>; } }
断点显示ApplyQueryAttributes方法内VideoList已正确填充,但在ViewModel其他方法中访问时抛出异常。
解决方案
1. 检查Video类的序列化兼容性
Shell导航传递对象时底层可能会尝试序列化,确保Video类满足:
- 拥有无参构造函数
- 所有需传递的属性为公共可读写
- 若使用自定义序列化,类需标记
[Serializable]或对应序列化特性
2. 移除构造函数中的集合初始化
接收端构造函数中提前实例化VideoList会覆盖传值逻辑的结果,建议修改构造函数:
public Constructor() { // 不初始化VideoList,由传值逻辑赋值 }
3. 确保ViewModel生命周期匹配
检查CreateCasePage的ViewModel实例逻辑:
- 确认页面
BindingContext在导航后赋值,而非提前创建 - 若用依赖注入,设置ViewModel为瞬态(Transient),保证每次导航生成新实例
4. 强类型转换并捕获异常
在ApplyQueryAttributes中替换as为强类型转换,便于排查转换问题:
public void ApplyQueryAttributes(IDictionary<string, object> query) { if (query.TryGetValue("VideoList", out var value)) { try { VideoList = (ObservableCollection<Video>)value; } catch (InvalidCastException ex) { System.Diagnostics.Debug.WriteLine($"类型转换失败:{ex.Message}"); } } }
5. 保证集合访问在主线程
若ViewModel其他方法涉及UI操作,需在主线程访问集合:
MainThread.BeginInvokeOnMainThread(() => { foreach(var video in VideoList) { // 处理UI相关逻辑 } });
内容的提问来源于stack exchange,提问作者Bob
相关产品推荐
相关产品推荐

