You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

MvvmCross双向绑定问题:nint与enum类型转换异常

Fix MvxValueConverter ConvertBack Exception When Binding UISegmentedControl to Enum in MvvmCross

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-int conversion works, and int implicitly converts to nint for UISegmentedControl.
  • When updating the ViewModel from the UI: The boxed int from the control is correctly cast by the base class, so your ConvertBack runs 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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.29 09:09:04