.NET MAUI Shell导航复用旧页面致数据重复问题求助
.NET MAUI Shell TabBar+子页面导航导致Clients页面数据重复的解决办法
问题根源分析
你碰到的核心问题是原Shell缓存清空逻辑没区分Tab切换和子页面导航:
- 从ClientsPage跳转到NewClientPage时,Shell的
CurrentItem?.CurrentItem?.CurrentItem还是Clients对应的ShellContent,导致_previousShellContent被设置为同一个对象。 - 后续从NewClientPage返回ClientsPage、再切换到MainPage,最后切回ClientsPage时,代码判断当前和上一个ShellContent是同一个,不会执行清空缓存操作;再加上ViewModel的
LoadClientsAsync是直接往集合里追加数据,自然就出现重复内容。
另外注意:ClientsPage.xaml.cs里的方法名写错了——await _viewModel.LoadClientAsync();应该是await _viewModel.LoadClientsAsync();,这个小错误也可能引发异常,先修正。
方案一:从ViewModel层面根治(最可靠)
直接修改LoadClientsAsync方法,每次加载前清空现有数据,从源头避免叠加:
public async Task LoadClientsAsync() { var clients = await _context.GetAllAsync<Client>(); // 先清空集合,再添加新数据 Clients ??= new ObservableCollection<Client>(); Clients.Clear(); if (clients is not null && clients.Any()) { foreach (var client in clients) { Clients.Add(client); } } }
这个方案完全不依赖Shell的缓存逻辑,稳定性最高,还规避了原方案用反射访问私有属性(ContentCache)的风险——私有API后续MAUI版本更新可能失效。
方案二:修复Shell的OnNavigated逻辑
如果坚持要保留页面缓存逻辑,修改导航判断,只在**Tab切换(ShellContent真正变化时)**清空上一个缓存:
public partial class AppShell : Shell { public AppShell() { InitializeComponent(); } ShellContent _previousShellContent; protected override void OnNavigated(ShellNavigatedEventArgs args) { base.OnNavigated(args); var currentShellContent = CurrentItem?.CurrentItem?.CurrentItem as ShellContent; // 仅当当前和上一个ShellContent不是同一个时,才清空缓存 if (currentShellContent != null && _previousShellContent != null && currentShellContent != _previousShellContent) { var contentCacheProperty = typeof(ShellContent) .GetProperty("ContentCache", BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.FlattenHierarchy); contentCacheProperty?.SetValue(_previousShellContent, null); } _previousShellContent = currentShellContent; } }
方案三:用Shell官方导航事件管理缓存(较优雅但仍依赖反射)
放弃手动跟踪ShellContent,改用Shell的导航事件判断Tab切换时机:
public AppShell() { InitializeComponent(); Navigated += AppShell_Navigated; } private void AppShell_Navigated(object sender, ShellNavigatedEventArgs e) { // 仅当Tab切换时(NavigationSource为ShellSectionChanged)清空上一个Tab的缓存 if (e.Source == NavigationSource.ShellSectionChanged) { var previousSection = e.Previous?.CurrentItem as ShellSection; if (previousSection != null) { foreach (var shellContent in previousSection.Items) { var contentCacheProperty = typeof(ShellContent) .GetProperty("ContentCache", BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.FlattenHierarchy); contentCacheProperty?.SetValue(shellContent, null); } } } }
优先推荐
优先选方案一,逻辑简单直接,完全不受Shell内部实现变化的影响,能彻底解决数据重复问题。
内容的提问来源于stack exchange,提问作者Ch1h0
相关产品推荐
相关产品推荐

