Xamarin.Forms:通过类型转换器传递枚举参数至URL失败问题排查
Xamarin.Forms Shell跳转传递枚举类型QueryProperty报错解决方法
问题场景与错误信息
页面定义了枚举类型的绑定属性,通过Shell的GoToAsync传递参数时,抛出InvalidCastException异常,提示无法将System.String转换为自定义枚举类型。
页面代码:
[QueryProperty(nameof(EnumProp), nameof(EnumProp))] public partial class MyPage : ContentPage { public static readonly BindableProperty EnumPropProperty = BindableProperty.Create(nameof(EnumProp), typeof(MyEnum), typeof(MyPage), propertyChanged: OnEnumPropChanged); public MyEnum EnumProp { get => (MyEnum)GetValue(EnumPropProperty); set => SetValue(EnumPropProperty, value); } }
跳转代码:
MyEnum enumProp = MyEnum.ThisValue; string dest = $"{nameof(MyPage)}?{nameof(MyPage.EnumProp)}={enumProp}"; await Shell.Current.GoToAsync(dest);
错误堆栈:
System.InvalidCastException HResult=0x80004002 Nachricht = Invalid cast from 'System.String' to 'XXX.MyEnum'. Quelle = System.Private.CoreLib Stapelüberwachung: bei System.Convert.DefaultToType(IConvertible value, Type targetType, IFormatProvider provider) bei Xamarin.Forms.ShellContent.ApplyQueryAttributes(Object content, IDictionary`2 query, IDictionary`2 oldQuery) bei Xamarin.Forms.BindableObject.SetValueCore(BindableProperty property, Object value, SetValueFlags attributes, SetValuePrivateFlags privateAttributes) bei Xamarin.Forms.BindableObject.SetValue(BindableProperty property, Object value, Boolean fromStyle, Boolean checkAccess) bei Xamarin.Forms.ShellNavigationManager.ApplyQueryAttributes(Element element, IDictionary`2 query, Boolean isLastItem, Boolean isPopping) bei Xamarin.Forms.ShellSection.<GoToAsync>d__69.MoveNext() bei Xamarin.Forms.ShellNavigationManager.<GoToAsync>d__13.MoveNext() bei XXX.MyPage.<ToDetail>d__17.MoveNext() in C:\Users\MyUser\Development\...\PackObjectItem.cs: Zeile46
此前给EnumProp属性添加TypeConverter特性未生效,原因是Shell处理QueryProperty时直接操作BindableProperty,而非属性的setter方法。
解决方案
方案一:给BindableProperty指定TypeConverter
修改BindableProperty的定义,在创建时直接指定typeConverter参数,同时实现对应的枚举转换类:
- 定义通用枚举转换器:
public class StringToEnumConverter<T> : TypeConverter where T : Enum { public override object ConvertFromInvariantString(string value) { if (string.IsNullOrWhiteSpace(value)) return default(T); return Enum.TryParse(typeof(T), value, ignoreCase: true, out var result) ? result : default(T); } }
- 修改BindableProperty定义:
public static readonly BindableProperty EnumPropProperty = BindableProperty.Create( nameof(EnumProp), typeof(MyEnum), typeof(MyPage), propertyChanged: OnEnumPropChanged, typeConverter: typeof(StringToEnumConverter<MyEnum>) );
方案二:通过中间字符串属性手动转换
定义一个字符串类型的中间属性接收Query参数,在其setter中手动将字符串转换为枚举类型:
[QueryProperty(nameof(EnumPropString), nameof(EnumProp))] public partial class MyPage : ContentPage { public static readonly BindableProperty EnumPropProperty = BindableProperty.Create(nameof(EnumProp), typeof(MyEnum), typeof(MyPage), propertyChanged: OnEnumPropChanged); public MyEnum EnumProp { get => (MyEnum)GetValue(EnumPropProperty); set => SetValue(EnumPropProperty, value); } // 中间属性,接收Query传递的字符串 public string EnumPropString { set { if (Enum.TryParse<MyEnum>(value, ignoreCase: true, out var enumValue)) { EnumProp = enumValue; } // 可添加无效值的默认处理逻辑 } } }
此方案无需额外实现转换器,通过手动转换避免类型异常。
内容的提问来源于stack exchange,提问作者Bernd Morgeneyer
相关产品推荐
相关产品推荐

