MAUI Shell中如何强制VerBarcosPage构造函数每次执行?
问题描述
我有如下XAML代码:
<Shell x:Class="ControlBarcos.AppShell" xmlns="http://schemas.microsoft.com/dotnet/2021/maui" xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml" xmlns:views="clr-namespace:ControlBarcos.Views" xmlns:local="clr-namespace:ControlBarcos" Shell.FlyoutBehavior="Flyout"> <Shell.BackButtonBehavior> <BackButtonBehavior IsEnabled="True" IsVisible="True"/> </Shell.BackButtonBehavior> <Shell.ItemTemplate> <DataTemplate> <Grid ColumnDefinitions="0.2*,0.8*"> <Image Source="{Binding Icon}" Margin="5" HeightRequest="25" WidthRequest="25"/> <Label Grid.Column="1" Text="{Binding Title}" FontAttributes="Bold" FontSize="Large" VerticalTextAlignment="Center" /> </Grid> </DataTemplate> </Shell.ItemTemplate> <ShellContent ContentTemplate="{DataTemplate views:InicialPage}" /> <FlyoutItem Title="Barcos" Icon="shipdos.png"> <Tab> <ShellContent ContentTemplate="{DataTemplate views:VerBarcosPage}" /> </Tab> </FlyoutItem> <FlyoutItem Title="Empresas Externas" Icon="humano.png"> <Tab> <ShellContent ContentTemplate="{DataTemplate views:VerEmpresasPage}" /> </Tab> </FlyoutItem> </Shell>
InicialPage仅用于显示logo。首次选择“Barcos”菜单选项时,VerBarcosPage的构造函数会被调用,但再次选择该选项时,构造函数不会执行。我需要让该构造函数每次都被调用,请问有什么解决方法?
VerBarcosPage的代码如下:
public partial class VerBarcosPage : ContentPage { public VerBarcosViewModel viewModel; public VerBarcosPage() { InitializeComponent(); viewModel = new VerBarcosViewModel(); BindingContext = viewModel; } }
解决方法
MAUI Shell默认会缓存页面实例,重复点击菜单不会重新创建页面,因此不会触发构造函数。以下是几种实现每次点击都触发构造函数的方案:
方案一:动态绑定创建新页面实例
修改Shell中ShellContent的定义,用属性绑定替代DataTemplate,每次访问属性时返回新的页面实例:
- 在AppShell后台代码中添加属性:
public VerBarcosPage VerBarcosPage => new VerBarcosPage(); public VerEmpresasPage VerEmpresasPage => new VerEmpresasPage();
- 修改XAML中的
ShellContent节点:
<FlyoutItem Title="Barcos" Icon="shipdos.png"> <Tab> <ShellContent Content="{Binding Source={RelativeSource AncestorType={x:Type local:AppShell}}, Path=VerBarcosPage}" /> </Tab> </FlyoutItem> <FlyoutItem Title="Empresas Externas" Icon="humano.png"> <Tab> <ShellContent Content="{Binding Source={RelativeSource AncestorType={x:Type local:AppShell}}, Path=VerEmpresasPage}" /> </Tab> </FlyoutItem>
每次点击菜单时,会调用属性的getter创建新页面实例,构造函数随之执行。
方案二:监听导航事件移除缓存页面
在AppShell中监听导航事件,导航前移除目标页面的缓存实例,迫使Shell重新创建页面:
- 在AppShell构造函数中添加事件监听:
public AppShell() { InitializeComponent(); Navigating += AppShell_Navigating; } private void AppShell_Navigating(object sender, ShellNavigatingEventArgs e) { // 处理VerBarcosPage导航 if (e.Target.Location.OriginalString.Contains(nameof(VerBarcosPage))) { var existingPage = Current.Items.FirstOrDefault(item => item.Content is VerBarcosPage); if (existingPage != null) { Current.Items.Remove(existingPage); } } // 同理处理VerEmpresasPage else if (e.Target.Location.OriginalString.Contains(nameof(VerEmpresasPage))) { var existingPage = Current.Items.FirstOrDefault(item => item.Content is VerEmpresasPage); if (existingPage != null) { Current.Items.Remove(existingPage); } } }
方案三:将初始化逻辑移至页面显示事件
如果不需要重建页面,仅需每次进入页面时执行初始化操作,可将构造函数中的逻辑迁移至Appearing事件:
修改VerBarcosPage代码:
public partial class VerBarcosPage : ContentPage { public VerBarcosViewModel viewModel; public VerBarcosPage() { InitializeComponent(); Appearing += VerBarcosPage_Appearing; } private void VerBarcosPage_Appearing(object sender, EventArgs e) { viewModel = new VerBarcosViewModel(); BindingContext = viewModel; // 其他需每次进入执行的逻辑 } }
这种方式无需修改Shell配置,适合仅需重置数据而非重建页面的场景。
内容的提问来源于stack exchange,提问作者user1803086
相关产品推荐
相关产品推荐

