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

Xamarin Forms Shell 导航返回时用户修改的邮箱输入数据被还原问题

问题根源

  1. Xamarin Forms Shell 存在默认特性:导航栈中的页面每次回到前台(即从下一级页面返回当前页)时,会自动将该页面初始导航时携带的Query参数重新赋值给对应QueryProperty,用户修改后的EmailAddress会被初始参数直接覆盖,这是值被还原的核心原因。
  2. 你在两个页面的XAML中分别实例化LoginViewModel,两个ViewModel为完全独立的实例,不存在数据共享,虽不是本次问题的直接诱因,但属于不规范写法。

解决方案

方案1:限制QueryProperty仅首次初始化时赋值

修改LoginViewModel,增加初始化标记,仅第一次接收Shell传递的参数时赋值,后续返回页面时不再覆盖用户修改的值:

[QueryProperty(nameof(EmailAddress), nameof(EmailAddress))]
public class LoginViewModel : BaseViewModel
{
    private bool _isEmailInitCompleted;
    private string emailAddress;
    public string EmailAddress
    {
        get => emailAddress;
        set
        {
            // 仅首次接收Shell导航参数时赋值,后续跳过
            if (!_isEmailInitCompleted)
            {
                SetProperty(ref emailAddress, Uri.UnescapeDataString(value));
                _isEmailInitCompleted = true;
                return;
            }
            // 用户手动修改输入框时正常赋值
            SetProperty(ref emailAddress, value);
        }
    }
}

方案2:页面后台接收参数,仅首次加载时赋值(更稳妥)

将参数接收逻辑从ViewModel迁移到页面后台,仅在页面首次加载时给ViewModel赋值,从根源避免重复覆盖的问题:

  1. 首先移除LoginViewModel上的[QueryProperty]特性,简化属性定义:
public class LoginViewModel : BaseViewModel
{
    private string emailAddress;
    public string EmailAddress
    {
        get => emailAddress;
        set => SetProperty(ref emailAddress, value);
    }
}
  1. 修改test1页面后台代码,接收参数并控制赋值时机,同时补充参数URL编码处理,避免特殊字符导致解析错误:
[QueryProperty(nameof(InitEmail), nameof(InitEmail))]
[XamlCompilation(XamlCompilationOptions.Compile)]
public partial class test1 : ContentPage
{
    public string InitEmail { get; set; }

    public test1()
    {
        InitializeComponent();
    }

    protected override void OnAppearing()
    {
        base.OnAppearing();
        // 仅首次加载时赋值初始邮箱
        if (!string.IsNullOrEmpty(InitEmail) && BindingContext is LoginViewModel vm && string.IsNullOrEmpty(vm.EmailAddress))
        {
            vm.EmailAddress = Uri.UnescapeDataString(InitEmail);
            InitEmail = null;
        }
    }

    private async void Button_Clicked(object sender, EventArgs e)
    {
        var email = txtEmail.Text;
        // 跳转前对参数做URL编码,避免特殊字符截断参数
        await Shell.Current.GoToAsync($"{nameof(test2)}?EmailAddress={Uri.EscapeDataString(email)}");
    }
}

可选优化:共享ViewModel实例

如果后续需要两个页面共享登录相关数据(如邮箱、密码),可以不用在XAML中分别实例化ViewModel,改为使用单例模式或者导航时传递同一个ViewModel实例,让两个页面操作同一份数据,无需重复传递参数。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.27 15:36:01