UWP中TabView切换时Page的OnLoaded事件重复触发问题咨询
这其实是WinUI TabView和WPF TabControl在内容管理机制上的差异导致的,我来帮你理清楚原因,再给你几个可行的解决办法:
为什么会重复触发OnLoaded?
WPF的TabControl默认会把所有Tab页的内容都保留在可视化树中,哪怕Tab没有被选中,所以Page的OnLoaded只会在首次加载时触发一次。
但WinUI的TabView默认有个内容卸载机制:当你切换到其他Tab时,当前未选中的TabViewItem的内容会被从可视化树中移除(相当于卸载)。当你切回这个Tab时,内容会重新被加载到可视化树里,这就导致了Page的OnLoaded事件再次被触发——因为对系统来说,这个Page相当于“重新进入了可视化树”。
另外你用Frame承载Page的方式,虽然每个Tab对应一个独立的Frame,但因为TabView的卸载行为,Frame里的Page也会跟着被卸载/重新加载,所以每次切换都会触发OnLoaded。
解决办法
方法1:关闭TabView的内容卸载行为
WinUI的TabView提供了一个专门的属性IsContentUnloadedOnTabChange,把它设为False,就能让非活跃Tab的内容保留在可视化树中,不会被卸载。这样Page的OnLoaded就只会在首次加载时触发一次。
修改你的MainPage XAML,给MainTabView加上这个属性:
<controls:TabView x:Name="MainTabView" IsContentUnloadedOnTabChange="False"> <!-- 原TabItems内容不变 --> </controls:TabView>
方法2:手动管理Page实例(适合需要更细粒度控制的场景)
如果你不想全局关闭所有Tab的内容卸载,或者需要复用Page实例,可以在后台代码中提前创建Page的实例,然后直接赋值给Frame的Content,而不是用SourcePageType。这样Frame会一直持有这个Page实例,不会因为Tab切换而重新创建或卸载。
比如修改MainPage的后台代码:
public sealed partial class MainPage : Page { public MainPage() { this.InitializeComponent(); // 提前创建Page3实例 var page3 = new Page3(); // 找到对应的TabViewItem里的Frame,赋值Content var tabItem3 = MainTabView.TabItems[1] as TabViewItem; if (tabItem3?.Content is Frame frame) { frame.Content = page3; } } }
同时记得把XAML中对应Frame的SourcePageType属性去掉,避免冲突。
验证效果
设置好之后,再切换Tab,你会发现Page的OnLoaded只会在首次加载时触发一次,切换时不会再重复触发了。
内容的提问来源于stack exchange,提问作者Hammas

