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

MvxTimePicker无法绑定TimeSpan问题求助

嘿,我之前在MvvmCross 6.0的Android项目里也碰到过MvxTimePicker绑定TimeSpan的问题,折腾了好一会儿才搞定,给你两个实用的解决方案:

方案1:使用双向值转换器

MvxTimePicker默认绑定的是Android原生的Time类型,而我们ViewModel里的属性是TimeSpan,所以需要一个双向值转换器来在两者之间做转换。

首先创建转换器类:

public class TimeToTimeSpanConverter : MvxValueConverter<TimeSpan, Time>, IMvxValueConverter
{
    protected override Time Convert(TimeSpan value, Type targetType, object parameter, CultureInfo culture)
    {
        var time = new Time();
        time.Hour = value.Hours;
        time.Minute = value.Minutes;
        time.Second = value.Seconds;
        return time;
    }

    protected override TimeSpan ConvertBack(Time value, Type targetType, object parameter, CultureInfo culture)
    {
        if (value == null)
            return TimeSpan.Zero;
        return new TimeSpan(value.Hour, value.Minute, value.Second);
    }
}

接下来在布局里引用这个转换器:

<MvxTimePicker
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    local:MvxBind="Time MyTimeSpanProperty, Converter=TimeToTimeSpan" />

最后别忘了在Setup.cs里注册转换器,让MvvmCross能找到它:

protected override void FillValueConverters(IMvxValueConverterRegistry registry)
{
    base.FillValueConverters(registry);
    registry.AddOrOverwrite("TimeToTimeSpan", new TimeToTimeSpanConverter());
}
方案2:自定义MvxTimeSpan绑定

如果觉得转换器不够直接,也可以自定义一个专门针对TimeSpan的绑定逻辑,这样布局里的写法会更简洁。

先创建绑定类:

public class MvxTimePickerTimeSpanBinding : MvxAndroidTargetBinding
{
    private readonly MvxTimePicker _timePicker;
    private IDisposable _subscription;

    public MvxTimePickerTimeSpanBinding(MvxTimePicker view) : base(view)
    {
        _timePicker = view;
    }

    public override Type TargetType => typeof(TimeSpan);

    public override MvxBindingMode DefaultMode => MvxBindingMode.TwoWay;

    protected override void SetValueImpl(object target, object value)
    {
        if (value is TimeSpan timeSpan)
        {
            var time = new Time();
            time.Hour = timeSpan.Hours;
            time.Minute = timeSpan.Minutes;
            time.Second = timeSpan.Seconds;
            _timePicker.Time = time;
        }
    }

    public override void SubscribeToEvents()
    {
        _subscription = _timePicker.TimeChangedObservable.Subscribe(OnTimeChanged);
    }

    private void OnTimeChanged(Time time)
    {
        var timeSpan = new TimeSpan(time.Hour, time.Minute, time.Second);
        FireValueChanged(timeSpan);
    }

    protected override void Dispose(bool isDisposing)
    {
        if (isDisposing)
        {
            _subscription?.Dispose();
            _subscription = null;
        }
        base.Dispose(isDisposing);
    }
}

然后在Setup.cs里注册这个自定义绑定:

protected override void FillTargetFactories(IMvxTargetBindingFactoryRegistry registry)
{
    base.FillTargetFactories(registry);
    registry.RegisterFactory(new MvxCustomBindingFactory<MvxTimePicker>("TimeSpan", view => new MvxTimePickerTimeSpanBinding(view)));
}

现在布局里就能直接绑定TimeSpan属性了:

<MvxTimePicker
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    local:MvxBind="TimeSpan MyTimeSpanProperty" />
额外注意点
  • 确保你的ViewModel属性是public TimeSpan MyTimeSpanProperty { get; set; },并且ViewModel继承自MvxViewModel(它已经实现了INotifyPropertyChanged,能自动通知UI更新)。
  • 如果你的TimeSpan可能超过24小时,记得额外处理,因为MvxTimePicker默认只支持0-23小时的范围。

内容的提问来源于stack exchange,提问作者Jim Wilcox

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.26 09:37:44