MAUI中TabbedPage绑定ViewModel引发NavigationFailed错误求助
问题回顾
未绑定ViewModel时TabbedPage运行正常,改为绑定ItemsSource和SelectedItem后,抛出Microsoft.UI.Xaml.Controls.Frame.NavigationFailed was unhandled异常。核心代码如下:
出错的HomePage.xaml绑定版本
<?xml version="1.0" encoding="utf-8" ?> <TabbedPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui" xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml" xmlns:page="clr-namespace:TabbedPageTest.Mvvm.Views" xmlns:viewmodels="clr-namespace:TabbedPageTest.Mvvm.ViewModels" x:Class="TabbedPageTest.Mvvm.Views.HomePage" Title="HomePage" x:Name="mainTabPage" Shell.NavBarIsVisible="False" ItemsSource="{Binding TabCollection}" SelectedItem="{Binding SelectedTab}"> <TabbedPage.BindingContext> <viewmodels:HomePageViewModel/> </TabbedPage.BindingContext> </TabbedPage>
HomePageViewModel核心代码
public partial class HomePageViewModel : BaseViewModel { public HomePageViewModel() { SetMainTabsTest(); } [ObservableProperty] public ObservableCollection<Page> _tabCollection = []; [ObservableProperty] public Page _selectedTab = null; private void SetMainTabsTest() { TabCollection.Clear(); TabCollection.Add(new HomeContentPage { Title = "Home" }); TabCollection.Add(new SettingsContentPage { Title = "Settings" }); SelectedTab = TabCollection[0]; } }
问题根源
直接在ViewModel构造函数中实例化Page对象并绑定给TabbedPage.ItemsSource,既违反MVVM职责分离原则,又会触发MAUI框架的导航生命周期异常——Page实例的创建和管理应由框架负责,而非ViewModel提前初始化。
解决方案
方法1:使用Tab数据模型绑定(推荐,符合MVVM)
通过封装页面元信息的模型实现绑定,避免直接操作Page实例:
- 创建TabItem数据模型:
public class TabItem { public string Title { get; set; } public Type PageType { get; set; } }
- 修改ViewModel绑定TabItem集合:
public partial class HomePageViewModel : BaseViewModel { public HomePageViewModel() { SetMainTabsTest(); } [ObservableProperty] public ObservableCollection<TabItem> _tabCollection = []; [ObservableProperty] public TabItem _selectedTab = null; private void SetMainTabsTest() { TabCollection.Clear(); TabCollection.Add(new TabItem { Title = "Home", PageType = typeof(HomeContentPage) }); TabCollection.Add(new TabItem { Title = "Settings", PageType = typeof(SettingsContentPage) }); SelectedTab = TabCollection[0]; } }
- 更新HomePage.xaml,通过DataTemplate生成页面:
<?xml version="1.0" encoding="utf-8" ?> <TabbedPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui" xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml" xmlns:page="clr-namespace:TabbedPageTest.Mvvm.Views" xmlns:viewmodels="clr-namespace:TabbedPageTest.Mvvm.ViewModels" x:Class="TabbedPageTest.Mvvm.Views.HomePage" Title="HomePage" x:Name="mainTabPage" Shell.NavBarIsVisible="False" ItemsSource="{Binding TabCollection}" SelectedItem="{Binding SelectedTab}"> <TabbedPage.BindingContext> <viewmodels:HomePageViewModel/> </TabbedPage.BindingContext> <TabbedPage.ItemTemplate> <DataTemplate> <ContentPage Title="{Binding Title}"> <ContentPage.Content> <ContentView> <x:TypeExtension Type="{Binding PageType}" /> </ContentView> </ContentPage.Content> </ContentPage> </DataTemplate> </TabbedPage.ItemTemplate> </TabbedPage>
方法2:推迟Page实例化到视图层
若需保留直接绑定Page的方式,将初始化逻辑移到视图生命周期事件中:
- 修改ViewModel,将初始化方法改为公共方法:
public partial class HomePageViewModel : BaseViewModel { public HomePageViewModel() { // 移除构造函数中的初始化代码 } [ObservableProperty] public ObservableCollection<Page> _tabCollection = []; [ObservableProperty] public Page _selectedTab = null; public void SetMainTabsTest() { TabCollection.Clear(); TabCollection.Add(new HomeContentPage { Title = "Home" }); TabCollection.Add(new SettingsContentPage { Title = "Settings" }); SelectedTab = TabCollection[0]; } }
- 在HomePage.xaml.cs中调用初始化:
protected override void OnAppearing() { base.OnAppearing(); if (BindingContext is HomePageViewModel vm) { vm.SetMainTabsTest(); } }
两种方法均可解决导航异常,推荐方法1以遵循MVVM设计模式。
内容的提问来源于stack exchange,提问作者DrCrazyApe
相关产品推荐
相关产品推荐

