Page
Page 是 WPF 中专为导航场景设计的轻量级内容容器,不能独立显示,必须放在 Frame 或 NavigationWindow 中,类似网页的 “页面”,支持前进 / 后退、生命周期、页面缓存与数据传递。
一、核心概念与定位
1. 本质与继承
- 继承链:
Page → ContentControl → Control → FrameworkElement - 本质:内容控件,只能有一个直接子元素(通常用
Grid/StackPanel包裹) - 核心定位:导航单元,用于构建多页式、向导式、浏览器式界面
2. 与 Window / UserControl 对比(关键区别)
| 特性 | Window | Page | UserControl |
|---|---|---|---|
| 独立运行 | ✅ 可直接启动 | ❌ 必须依赖 Frame/NavigationWindow | ❌ 需嵌入容器 |
| 窗口边框 | ✅ 自带标题栏 / 边框 | ❌ 无任何窗口装饰 | ❌ 无 |
| 导航支持 | ❌ 无内置导航 | ✅ 内置 NavigationService、前进 / 后退栈 |
❌ 无 |
| 生命周期 | Loaded/Closing/Closed | OnNavigatedTo/From、Navigating | Loaded/Unloaded |
| 适用场景 | 主窗口、独立弹窗 | 多页导航、向导、内容浏览 | 复用 UI 模块、局部组件 |
3. 必须的宿主容器
Page 不能单独显示,必须放在以下两种容器中:- Frame:最常用,可嵌入 Window/UserControl/Page 任意位置,支持局部导航
- NavigationWindow:自带导航栏(前进 / 后退)的顶层窗口,适合全屏导航应用
二、Page 常用属性
| 属性 | 作用 | 常用值 |
|---|---|---|
Title |
页面标题(可同步到宿主窗口标题) | 字符串 |
Background |
页面背景 | 颜色 / 画刷 |
FontFamily/FontSize |
页面默认字体 | 系统字体 / 数值 |
NavigationService |
导航服务(只读,用于代码导航) | NavigationService 对象 |
KeepAlive |
是否在导航历史中保留实例(缓存) | True/False(默认 False) |
ShowsNavigationUI |
是否显示宿主的导航 UI(前进 / 后退) | True/False |
三、Page 核心生命周期(导航事件)
Page 有专属的导航生命周期,比 Window 更精细:- Navigating:导航开始前触发(可拦截跳转)
- Navigated:导航完成后触发(页面已加载)
- LoadCompleted:页面内容完全加载后触发
- OnNavigatedTo:页面被导航到时触发(初始化数据首选)
- OnNavigatedFrom:页面被导航离开时触发(保存数据)
- Unloaded:页面卸载时触发
四、导航核心:NavigationService
每个 Page 都有
NavigationService 属性,用于代码控制导航:- Navigate(Page/Uri):跳转到指定页面
- GoBack():后退(需判断
CanGoBack) - GoForward():前进(需判断
CanGoForward) - Journal:导航历史栈(前进 / 后退记录)
- StopLoading():停止加载
- Refresh():刷新当前页面
五、完整实战示例(Frame + 多 Page 导航)
步骤 1:创建 WPF 项目
新建 WPF 应用,添加 3 个 Page:
HomePage.xaml、Page1.xaml、Page2.xaml示例 1:主窗口(含 Frame 容器)
1 <!-- MainWindow.xaml --> 2 <Window x:Class="WpfPageDemo.MainWindow" 3 xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 4 xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 5 Title="WPF Page 导航演示" Height="600" Width="800" 6 WindowStartupLocation="CenterScreen"> 7 <Grid> 8 <!-- 顶部导航栏 --> 9 <StackPanel Orientation="Horizontal" VerticalAlignment="Top" Background="#f0f0f0" Padding="10"> 10 <Button Content="首页" Click="BtnHome_Click" Margin="5"/> 11 <Button Content="页面1" Click="BtnPage1_Click" Margin="5"/> 12 <Button Content="页面2" Click="BtnPage2_Click" Margin="5"/> 13 <Button Content="后退" Click="BtnBack_Click" Margin="5"/> 14 <Button Content="前进" Click="BtnForward_Click" Margin="5"/> 15 </StackPanel> 16 17 <!-- Frame 容器:承载所有 Page --> 18 <Frame x:Name="MainFrame" 19 Margin="0,60,0,0" 20 NavigationUIVisibility="Hidden" <!-- 隐藏默认导航栏 --> 21 Background="White"/> 22 </Grid> 23 </Window>
1 // MainWindow.xaml.cs 2 using System; 3 using System.Windows; 4 using WpfPageDemo.Pages; 5 6 namespace WpfPageDemo 7 { 8 public partial class MainWindow : Window 9 { 10 public MainWindow() 11 { 12 InitializeComponent(); 13 // 初始加载首页 14 MainFrame.Navigate(new HomePage()); 15 } 16 17 // 导航到首页 18 private void BtnHome_Click(object sender, RoutedEventArgs e) 19 { 20 MainFrame.Navigate(new HomePage()); 21 } 22 23 // 导航到页面1 24 private void BtnPage1_Click(object sender, RoutedEventArgs e) 25 { 26 MainFrame.Navigate(new Page1()); 27 } 28 29 // 导航到页面2 30 private void BtnPage2_Click(object sender, RoutedEventArgs e) 31 { 32 MainFrame.Navigate(new Page2()); 33 } 34 35 // 后退 36 private void BtnBack_Click(object sender, RoutedEventArgs e) 37 { 38 if (MainFrame.CanGoBack) MainFrame.GoBack(); 39 } 40 41 // 前进 42 private void BtnForward_Click(object sender, RoutedEventArgs e) 43 { 44 if (MainFrame.CanGoForward) MainFrame.GoForward(); 45 } 46 } 47 }
示例 2:首页 Page(HomePage.xaml)
1 <Page x:Class="WpfPageDemo.Pages.HomePage" 2 xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 3 xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 4 Title="首页" 5 KeepAlive="True"> <!-- 缓存页面实例,导航回来不重新创建 --> 6 <Grid Background="LightBlue"> 7 <TextBlock Text="这是首页" FontSize="30" 8 HorizontalAlignment="Center" VerticalAlignment="Center"/> 9 <Button Content="跳转到页面1" Click="BtnGoPage1_Click" 10 Width="150" Height="40" VerticalAlignment="Bottom" Margin="20"/> 11 </Grid> 12 </Page>
1 // HomePage.xaml.cs 2 using System.Windows; 3 using System.Windows.Controls; 4 5 namespace WpfPageDemo.Pages 6 { 7 public partial class HomePage : Page 8 { 9 public HomePage() 10 { 11 InitializeComponent(); 12 } 13 14 // 页面内导航到 Page1 15 private void BtnGoPage1_Click(object sender, RoutedEventArgs e) 16 { 17 this.NavigationService.Navigate(new Page1()); 18 } 19 20 // 页面被导航到(初始化) 21 protected override void OnNavigatedTo(System.Windows.Navigation.NavigationEventArgs e) 22 { 23 base.OnNavigatedTo(e); 24 MessageBox.Show("进入首页!"); 25 } 26 27 // 页面被导航离开(保存数据) 28 protected override void OnNavigatedFrom(System.Windows.Navigation.NavigationEventArgs e) 29 { 30 base.OnNavigatedFrom(e); 31 MessageBox.Show("离开首页!"); 32 } 33 } 34 }
示例 3:页面 1(Page1.xaml,含拦截导航)
1 <Page x:Class="WpfPageDemo.Pages.Page1" 2 xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 3 xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 4 Title="页面1"> 5 <Grid Background="LightGreen"> 6 <TextBlock Text="这是页面1" FontSize="30" 7 HorizontalAlignment="Center" VerticalAlignment="Center"/> 8 <Button Content="跳转到页面2" Click="BtnGoPage2_Click" 9 Width="150" Height="40" VerticalAlignment="Bottom" Margin="20"/> 10 </Grid> 11 </Page>
1 // Page1.xaml.cs 2 using System.Windows; 3 using System.Windows.Controls; 4 using System.Windows.Navigation; 5 6 namespace WpfPageDemo.Pages 7 { 8 public partial class Page1 : Page 9 { 10 public Page1() 11 { 12 InitializeComponent(); 13 // 注册导航开始事件(可拦截) 14 this.NavigationService.Navigating += NavigationService_Navigating; 15 } 16 17 private void BtnGoPage2_Click(object sender, RoutedEventArgs e) 18 { 19 this.NavigationService.Navigate(new Page2()); 20 } 21 22 // 导航开始前触发(可拦截跳转) 23 private void NavigationService_Navigating(object sender, NavigatingCancelEventArgs e) 24 { 25 MessageBoxResult result = MessageBox.Show("确定要离开页面1吗?", "提示", 26 MessageBoxButton.YesNo); 27 if (result == MessageBoxResult.No) 28 { 29 e.Cancel = true; // 拦截导航,不跳转 30 } 31 } 32 } 33 }
示例 4:页面 2(Page2.xaml,最简单)
1 <Page x:Class="WpfPageDemo.Pages.Page2" 2 xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 3 xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 4 Title="页面2"> 5 <Grid Background="LightCoral"> 6 <TextBlock Text="这是页面2" FontSize="30" 7 HorizontalAlignment="Center" VerticalAlignment="Center"/> 8 </Grid> 9 </Page>
六、关键知识点详解
1. Page 内容限制
同 Window,只能有一个直接子元素,必须用布局容器包裹:
1 <!-- 错误 --> 2 <Page> 3 <TextBlock/> 4 <Button/> 5 </Page> 6 7 <!-- 正确 --> 8 <Page> 9 <Grid> 10 <TextBlock/> 11 <Button/> 12 </Grid> 13 </Page>
2. 导航的两种方式
(1)代码导航(最常用)
1 // 方式1:导航到 Page 实例 2 this.NavigationService.Navigate(new Page1()); 3 4 // 方式2:通过 URI 导航(XAML路径) 5 this.NavigationService.Navigate(new Uri("Pages/Page1.xaml", UriKind.Relative)); 6 7 // 方式3:Frame 直接导航 8 MainFrame.Navigate(new Page1());
(2)XAML 超链接导航
1 <Hyperlink NavigateUri="Pages/Page1.xaml">跳转到页面1</Hyperlink>
3. 页面缓存(KeepAlive)
KeepAlive="True":导航历史中保留 Page 实例,返回时不重新创建(状态保留)KeepAlive="False"(默认):每次导航都创建新实例(适合无状态页面)
4. 页面间数据传递
(1)构造函数传值(推荐)
1 // 发送页 2 MainFrame.Navigate(new Page2("来自首页的数据")); 3 4 // 接收页 Page2 5 public Page2(string data) 6 { 7 InitializeComponent(); 8 txtData.Text = data; 9 }
(2)NavigationService 传值
1 // 发送 2 this.NavigationService.Navigate(new Page2(), "传递的数据"); 3 4 // 接收(OnNavigatedTo) 5 protected override void OnNavigatedTo(NavigationEventArgs e) 6 { 7 string data = e.ExtraData as string; 8 }
(3)全局变量 / ViewModel(MVVM 推荐)
5. NavigationWindow 使用(全屏导航)
1 <!-- NavigationWindow.xaml --> 2 <NavigationWindow x:Class="WpfPageDemo.MainNavWindow" 3 xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 4 xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 5 Title="导航窗口" Height="600" Width="800" 6 Source="Pages/HomePage.xaml"> <!-- 初始页面 --> 7 </NavigationWindow>
1 // App.xaml 修改启动窗口 2 StartupUri="MainNavWindow.xaml"
七、总结
- Page 是 WPF 导航专用的轻量级内容容器,必须依赖
Frame/NavigationWindow显示 - 核心能力:导航历史、生命周期、页面缓存、数据传递
- 适用场景:多页应用、向导、设置界面、内容浏览、帮助系统
- 关键 API:
NavigationService(导航控制)、OnNavigatedTo/From(生命周期)、KeepAlive(缓存)
浙公网安备 33010602011771号