Shell导航传递ImageSource参数报错:如何单独传递该对象?
问题:Shell导航单独传递ImageSource对象时抛出InvalidCastException异常
尝试通过Shell导航将ImageSource对象单独传递到另一页面时,执行以下代码:
await Shell.Current.GoToAsync($"{nameof(FullScreenImagePage)}?", new Dictionary<string, object> { ["TempImageSource"] = TempPhotoPoint.ExamplePicture });
抛出异常:
System.InvalidCastException: 'Object must implement IConvertible.'
其中ExamplePicture为ImageSource类型,FullScreenImagePage的ViewModel配置如下:
[QueryProperty(nameof(TempImageSource), nameof(TempImageSource))]
[ObservableProperty] ImageSource tempImageSource;
ViewModel已通过BindingContext与页面关联,传递包含ImageSource的TempPhotoPoint对象时一切正常,询问如何单独传递ImageSource对象。
原因分析
Shell导航的查询参数机制默认要求传递的对象实现IConvertible接口,而ImageSource并未实现该接口,直接传递会触发类型转换异常;但传递包含ImageSource的完整对象时,Shell会将其作为导航参数的整体对象传递,绕过了IConvertible的校验逻辑,因此可以正常工作。
解决方法
方案1:使用NavigationParameters传递复杂对象
利用Shell的NavigationParameters传递复杂对象,无需实现IConvertible:
- 修改导航代码:
var parameters = new NavigationParameters(); parameters.Add("TempImageSource", TempPhotoPoint.ExamplePicture); await Shell.Current.GoToAsync(nameof(FullScreenImagePage), parameters);
- 在ViewModel中实现
INavigatedAware接口接收参数:
public class FullScreenImageViewModel : INavigatedAware { [ObservableProperty] ImageSource tempImageSource; public void OnNavigatedTo(NavigatedToEventArgs args) { if (args.Parameter is NavigationParameters navParams && navParams.ContainsKey("TempImageSource")) { TempImageSource = navParams["TempImageSource"] as ImageSource; } } public void OnNavigatedFrom(NavigatedFromEventArgs args) { // 可选实现导航离开时的逻辑 } }
方案2:将ImageSource转换为可序列化的字符串传递
如果必须使用查询参数,可根据ImageSource的具体类型(如UriImageSource或FileImageSource)转换为字符串传递,再在目标页面重构:
- 导航代码:
string imageParam = string.Empty; if (TempPhotoPoint.ExamplePicture is UriImageSource uriSource) { imageParam = uriSource.Uri.AbsoluteUri; } else if (TempPhotoPoint.ExamplePicture is FileImageSource fileSource) { imageParam = fileSource.File; } await Shell.Current.GoToAsync($"{nameof(FullScreenImagePage)}?TempImageSource={imageParam}");
- ViewModel中处理字符串参数并重构ImageSource:
[QueryProperty(nameof(TempImageSourceString), "TempImageSource")] public partial class FullScreenImageViewModel : ObservableObject { [ObservableProperty] string tempImageSourceString; [ObservableProperty] ImageSource tempImageSource; partial void OnTempImageSourceStringChanged(string value) { if (string.IsNullOrEmpty(value)) return; if (Uri.TryCreate(value, UriKind.Absolute, out var uri)) { TempImageSource = ImageSource.FromUri(uri); } else { TempImageSource = ImageSource.FromFile(value); } } }
方案3:将ImageSource包装到简单对象中传递
模仿之前传递TempPhotoPoint的方式,把ImageSource包装到一个仅包含该属性的类中:
- 定义包装类:
public class ImageSourceWrapper { public ImageSource Source { get; set; } }
- 修改导航代码:
await Shell.Current.GoToAsync(nameof(FullScreenImagePage), new Dictionary<string, object> { ["ImageWrapper"] = new ImageSourceWrapper { Source = TempPhotoPoint.ExamplePicture } });
- ViewModel接收并提取ImageSource:
[QueryProperty(nameof(ImageWrapper), "ImageWrapper")] public partial class FullScreenImageViewModel : ObservableObject { [ObservableProperty] ImageSourceWrapper imageWrapper; [ObservableProperty] ImageSource tempImageSource; partial void OnImageWrapperChanged(ImageSourceWrapper value) { TempImageSource = value?.Source; } }
内容的提问来源于stack exchange,提问作者Christian Lindenblatt
相关产品推荐
相关产品推荐

