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

MAUI Shell导航:首次跳转后Dictionary传递对象为null的问题

MAUI页面二次跳转时QueryProperty传递对象为null问题

问题现象

首次点击按钮调用OpenSpecialInstructionsCommand可正常跳转至SpecialInstructions页面并加载内容,但返回主页面后再次跳转,目标页面的LineItem对象变为null,导致页面因LineItem.StockNumber为空无法执行加载逻辑,陷入无限加载状态。

相关代码

主ViewModel导航代码

[RelayCommand]
async Task OpenSpecialInstructions()
{
   if (LineItem == null)
      return;

   this.popupPage.Close();

   await Shell.Current.GoToAsync(nameof(SpecialInstructions), true, new Dictionary<string, object>
   {
       {"LineItem", LineItem }
   });
}

注:每次调用该方法时,LineItem均持有有效数据

目标ViewModel代码

[QueryProperty(nameof(LineItem), "LineItem")]

public partial class SpecialInstructionsViewModel : BaseViewModel
{
   [ObservableProperty]
   LineItem lineItem;

   [RelayCommand]
   async Task Instructions_Get()
   {
      IsBusy = true;
      if (App.SpecialInstructions.Count() == 0)
      {
         await PrefillSpecialInstructions();
      }
      SpecialInstructions = App.SpecialInstructions;
      foreach (SpecialInstruction instruction in App.DbConnection.SpecialInstructions_Get(LineItem.StockNumber))
      {
         try { SpecialInstructions.FirstOrDefault(x => x.MessageCode == instruction.MessageCode).IsSelected = true; } catch { }
      }
      IsBusy = false;
   }
}

注:二次跳转时,LineItem在执行SpecialInstructions = App.SpecialInstructions;前始终为null

原因分析

  1. Shell页面缓存机制:MAUI Shell默认会缓存页面实例,首次跳转创建的SpecialInstructionsViewModel在返回后不会被销毁,二次跳转时复用该实例,但QueryProperty的赋值时机晚于Instructions_Get的执行,导致加载逻辑触发时LineItem尚未被赋值。
  2. 加载逻辑触发时机错误:如果Instructions_Get是在页面初始化时自动执行(如绑定到页面Loaded事件),二次进入时缓存的ViewModel中LineItem未被重新赋值,直接执行加载就会出现null。
  3. 对象序列化问题:LineItem类若不具备可序列化特性,Shell导航二次传递对象时可能失败,导致LineItem为null。

解决办法

1. 禁用页面缓存,强制创建新实例

修改导航代码,添加清除缓存参数:

await Shell.Current.GoToAsync(nameof(SpecialInstructions), true, new Dictionary<string, object>
{
    {"LineItem", LineItem },
    {"clearCache", true}
});

或者在路由注册时配置禁用缓存:

Routing.RegisterRoute(nameof(SpecialInstructions), typeof(SpecialInstructions), 
    new Dictionary<string, object>{{nameof(NavigationCacheMode), NavigationCacheMode.Disabled}});

2. 监听LineItem变更再执行加载

利用ObservableProperty的变更回调,确保只有当LineItem被正确赋值后才触发加载逻辑:

[ObservableProperty]
LineItem lineItem;

// 自动生成的属性变更回调(需确保启用CommunityToolkit.Mvvm的源生成)
partial void OnLineItemChanged(LineItem value)
{
    if (value != null)
    {
        _ = Instructions_Get();
    }
}

同时移除页面初始化时自动调用Instructions_Get的逻辑,避免提前执行加载。

3. 手动清理导航栈中的缓存页面

在主页面的返回逻辑中,移除已缓存的SpecialInstructions页面:

var targetPage = Shell.Current.Navigation.NavigationStack.FirstOrDefault(p => p.GetType() == typeof(SpecialInstructions));
if (targetPage != null)
{
    Shell.Current.Navigation.RemovePage(targetPage);
}

4. 确保LineItem可序列化

为LineItem类添加可序列化标记,并保证所有属性为公共可读写:

[Serializable]
public class LineItem
{
    public string StockNumber { get; set; }
    // 其他属性...
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.19 03:10:41