MvvmCross双向绑定问题:nint与enum类型转换异常
Let's break down what's going wrong and fix it quickly:
The Root Cause
Your exception happens because the generic MvxValueConverter<TFrom, TTo> base class tries to perform a forced cast on a boxed value before your custom ConvertBack runs.
UISegmentedControl's SelectedSegment is a nint, but during binding, it gets boxed as an int (a common quirk in Xamarin.iOS bindings). Your converter uses MvxValueConverter<MyViewModel.Selection, nint>, so the base class tries to cast the boxed int directly to nint—which throws an InvalidCastException because you can't unbox an int directly to a nint struct. That's why your ConvertBack code never even gets called.
Solution 1: Use int Instead of nint in the Converter
Since your enum values are small (0,1,2), int and nint are compatible across 32/64-bit systems. This is the simplest fix:
Update your SelectionValueConverter to target int instead of nint:
public class SelectionValueConverter : MvxValueConverter<MyViewModel.Selection, int> { protected override int Convert(MyViewModel.Selection value, Type targetType, object parameter, CultureInfo culture) { return (int)value; } protected override MyViewModel.Selection ConvertBack(int value, Type targetType, object parameter, CultureInfo culture) { return (MyViewModel.Selection)value; } }
Why this works:
- When updating the UI from the ViewModel: The enum-to-
intconversion works, andintimplicitly converts tonintfor UISegmentedControl. - When updating the ViewModel from the UI: The boxed
intfrom the control is correctly cast by the base class, so yourConvertBackruns as expected.
Solution 2: Use Non-Generic MvxValueConverter (For Strict nint Handling)
If you need to strictly work with nint (e.g., for large segment counts), skip the generic base class and handle all type conversions yourself:
public class SelectionValueConverter : MvxValueConverter { public override object Convert(object value, Type targetType, object parameter, CultureInfo culture) { if (value is MyViewModel.Selection selection) { return (nint)selection; } return 0; } public override object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) { int intValue; // Handle both boxed int and nint cases if (value is nint nintVal) { intValue = (int)nintVal; } else if (value is int intVal) { intValue = intVal; } else { throw new ArgumentException($"Unsupported value type: {value.GetType().Name}"); } return (MyViewModel.Selection)intValue; } }
This bypasses the generic base class's problematic casting step and lets you handle all input types explicitly.
Your Binding Code Stays the Same
No changes needed here—your existing binding setup will work with either converter:
var set = this.CreateBindingSet<MyView, MyViewModel>(); set.Bind(SegmentedControl).To(vm => vm.SelectedSegment).WithConversion(new SelectionValueConverter()); set.Apply();
内容的提问来源于stack exchange,提问作者Ivan Mir

