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

如何通过QueryProperty在XAML页面间传递TimeSpan并解决转换异常?

解决System.InvalidCastException: 无法将'System.String'转换为'System.TimeSpan'的问题

错误原因

使用Xamarin.Forms Shell的GoToAsync传递导航参数时,所有参数都会被序列化为字符串类型。而你在目标页面ViewModel中直接用[QueryProperty]绑定TimeSpan类型的属性,Shell的参数绑定机制无法自动完成字符串到TimeSpan的转换,因此抛出类型转换异常。


解决方案1:使用中间字符串属性转换

在目标ViewModel中添加一个字符串类型的中间属性,用来接收查询参数,再手动转换为TimeSpan赋值给目标属性:

修改第二个页面的ViewModel

using System;
using System.ComponentModel;
using Xamarin.Forms;

namespace TestApp2.ViewModels
{
    // 绑定到中间字符串属性
    [QueryProperty(nameof(TimeString), nameof(TransferDateTimePageViewModel.Time))]
    public class TransferDateTimePageViewModel : BaseViewModel, INotifyPropertyChanged
    {
        private TimeSpan time;
        public TimeSpan Time
        {
            get => time;
            set
            {
                time = value;
                OnPropertyChanged();
            }
        }

        // 接收字符串参数的中间属性
        private string timeString;
        public string TimeString
        {
            get => timeString;
            set
            {
                timeString = value;
                // 安全解析字符串为TimeSpan
                if (TimeSpan.TryParse(timeString, out TimeSpan parsedTime))
                {
                    Time = parsedTime;
                }
                OnPropertyChanged();
            }
        }

        public TransferDateTimePageViewModel()
        {
        }
    }
}

优化第一个页面的跳转代码(可选但推荐)

为了确保TimeSpan的字符串格式可被正确解析,使用标准格式字符串传递参数:

async void OnTimePickerSelected()
{
    // 使用TimeSpan的标准格式字符串("c"表示ISO 8601格式)
    await Shell.Current.GoToAsync($"{nameof(TransferDateTimePage)}?" +
        $"{nameof(TransferDateTimePageViewModel.Time)}={Time.ToString("c")}");
}

注:原代码中的if (time != null)可以删除,因为TimeSpan是值类型,永远不会为null。


解决方案2:实现IQueryAttributable接口手动处理参数

通过实现IQueryAttributable接口,直接在ViewModel中处理导航查询参数,无需依赖[QueryProperty]特性:

修改第二个页面的ViewModel

using System;
using System.Collections.Generic;
using System.ComponentModel;
using Xamarin.Forms;

namespace TestApp2.ViewModels
{
    public class TransferDateTimePageViewModel : BaseViewModel, INotifyPropertyChanged, IQueryAttributable
    {
        private TimeSpan time;
        public TimeSpan Time
        {
            get => time;
            set
            {
                time = value;
                OnPropertyChanged();
            }
        }

        public TransferDateTimePageViewModel()
        {
        }

        // 实现接口方法,手动解析查询参数
        public void ApplyQueryAttributes(IDictionary<string, string> query)
        {
            if (query.TryGetValue(nameof(Time), out string timeString))
            {
                if (TimeSpan.TryParse(timeString, out TimeSpan parsedTime))
                {
                    Time = parsedTime;
                }
            }
        }
    }
}

此方案下可以删除ViewModel上的[QueryProperty]特性。


效果验证

修改完成后,从第一个页面跳转时,TimeSpan会被序列化为字符串传递,目标页面ViewModel会将字符串解析回TimeSpan并绑定到TimePicker,即可正常显示和编辑时间,不会再抛出类型转换异常。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.10 13:48:12