WPF 入门教程(四)

2026-05-16 01:00 269 阅读

十二.进阶属性

1.依赖属性

扩展传统的.NET属性系统,为WPF的数据绑定、样式、动画等高级功能提供了基础支持。 属性快捷键

// prop 属性
public int MyProperty { get; set; }

// propi 只能初始化属性(只能在构造函数和初始属性上初始化)
public int MyProperty1 { get; init; }

// propg 只能在当前类中设置属性
public int MyProperty2 { get; private set; }


// propfull 完整属性
private int myVar;
public int Myvar
{
    get { return myVar; }
    set { myVar = value; }
}
// propdp 依赖属性
// propa 附加属性

1.1 自定义文本框

1.1.1 创建MyTextBox

public class MyTextBox:TextBox
{
    private string _initPlaceHolder = string.Empty;
    public string PlaceHolder
    {
        get { return (string)GetValue(PlaceHolderProperty); }
        set { SetValue(PlaceHolderProperty, value); }
    }

    public static readonly DependencyProperty PlaceHolderProperty =
        DependencyProperty.Register(nameof(PlaceHolder), typeof(string), typeof(MyTextBox),
            new PropertyMetadata(default(string)));

    protected override void OnRender(DrawingContext drawingContext)
    {
        base.OnRender(drawingContext);
        _initPlaceHolder = PlaceHolder;
    }

    protected override void OnTextChanged(TextChangedEventArgs e)
    {
        base.OnTextChanged(e);
        PlaceHolder=string.IsNullOrWhiteSpace(Text) ? _initPlaceHolder : string.Empty;
    }
}

1.1.2 新建样式

<Style x:Key="myTextBox" TargetType="controls:MyTextBox">
    <Setter Property="PlaceHolder" Value="请输入..."/>
    <Setter Property="Width" Value="180"/>
    <Setter Property="Height" Value="30"/>
    <Setter Property="VerticalContentAlignment" Value="Center"/>
    <Setter Property="Template">
        <Setter.Value>
            <ControlTemplate TargetType="controls:MyTextBox">
                <Border BorderBrush="{TemplateBinding BorderBrush}" 
                        Width="{TemplateBinding Width}"
                        Height="{TemplateBinding Height}"
                        BorderThickness="{TemplateBinding BorderThickness}">
                    <ScrollViewer x:Name="PART_ContentHost"/>
                    <Border.Background>
                        <VisualBrush Stretch="None" Opacity="0.5" AlignmentX="Left" AlignmentY="Center">
                            <VisualBrush.Visual>
                                <TextBlock Text="{TemplateBinding PlaceHolder}"/>
                            </VisualBrush.Visual>
                        </VisualBrush>
                    </Border.Background>
                </Border>
            </ControlTemplate>
        </Setter.Value>
    </Setter>
</Style>

1.1.3 使用

<controls:MyTextBox PlaceHolder="请输入内容..." Style="{StaticResource myTextBox}"/>

2.附加属性

附加属性是一种特殊类型的依赖属性,可以被"附加"到任何对象上,即使该对象本身没有定义这个属性。 经典场景

<TextBlock Grid.Row="1"/>

2.1 WatermarkHelper

public class WatermarkHelper
{
    // 定义附加属性
    public static readonly DependencyProperty WatermarkProperty =
        DependencyProperty.RegisterAttached(
            "Watermark",
            typeof(string),
            typeof(WatermarkHelper),
            new PropertyMetadata(string.Empty, OnWatermarkChanged));

    // Get方法
    public static string GetWatermark(DependencyObject obj)
    {
        return (string)obj.GetValue(WatermarkProperty);
    }

    // Set方法
    public static void SetWatermark(DependencyObject obj, string value)
    {
        obj.SetValue(WatermarkProperty, value);
    }

    // 属性变更回调
    private static void OnWatermarkChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
    {
        if (d is TextBox textBox)
        {
            // 当水印文本变化时更新显示
            if (string.IsNullOrEmpty(textBox.Text))
            {
                textBox.Text = e.NewValue as string;
                textBox.Foreground = Brushes.Gray;
            }

            textBox.GotFocus += (s, args) =>
            {
                if (textBox.Text == GetWatermark(textBox))
                {
                    textBox.Text = string.Empty;
                    textBox.Foreground = Brushes.Black;
                }
            };

            textBox.LostFocus += (s, args) =>
            {
                if (string.IsNullOrEmpty(textBox.Text))
                {
                    textBox.Text = GetWatermark(textBox);
                    textBox.Foreground = Brushes.Gray;
                }
            };
        }
    }
}
 <StackPanel>
     <TextBox helpers:WatermarkHelper.Watermark="请输入内容..." Width="200" Height="50"/>
     <TextBox helpers:WatermarkHelper.Watermark="请输入内容2..." Width="200" Height="50"/>
 </StackPanel>

3.路由事件

路由事件(Routed Event)是WPF中一个核心概念,它允许事件在可视化树中"路由"传递,为事件处理提供了更灵活的方式。

3.1 基本概念

路由方向​​:

  • 冒泡(Bubbling):从事件源向上传递到根元素
  • 隧道(Tunneling):从根元素向下传递到事件源
  • 直接(Direct):仅在事件源处理,不路由

​​事件处理机制​​:

  • 允许在父元素上处理子元素的事件
  • 支持事件处理器共享
  • 提供更灵活的事件处理方式

3.2 路由类型

冒泡事件

// 示例:Button的Click事件是冒泡事件
<StackPanel Button.Click="StackPanel_Click">
    <Button Content="点击我" />
</StackPanel>

隧道事件

// 示例:PreviewMouseDown是隧道事件
<StackPanel PreviewMouseDown="StackPanel_PreviewMouseDown">
    <Button Content="点击我" />
</StackPanel>

直接事件

// 示例:大多数标准事件都是直接事件
<Button Click="Button_Click" />

3.3 自定义路由事件

public class MyButton : Button
{
    // 1. 注册路由事件
    public static readonly RoutedEvent TapEvent = 
        EventManager.RegisterRoutedEvent(
            "Tap",                              // 事件名称
            RoutingStrategy.Bubble,             // 路由策略
            typeof(RoutedEventHandler),         // 事件处理程序类型
            typeof(MyButton));                  // 拥有者类型
    
    // 2. 提供CLR事件包装器
    public event RoutedEventHandler Tap
    {
        add { AddHandler(TapEvent, value); }
        remove { RemoveHandler(TapEvent, value); }
    }
    
    // 3. 触发事件的方法
    protected virtual void OnTap()
    {
        RoutedEventArgs args = new RoutedEventArgs(TapEvent, this);
        RaiseEvent(args);
    }
}

十三.转换

WPF转换(Transform)是用于改变UI元素位置、大小、旋转和倾斜等视觉效果的机制。所有继承自UIElement的控件都支持转换。 转换类型:

  • ​​TranslateTransform​​ - 平移转换
  • ​​RotateTransform​​ - 旋转转换
  • ​​ScaleTransform​​ - 缩放转换
  • ​​SkewTransform​​ - 倾斜转换
  • ​​MatrixTransform​​ - 矩阵转换
  • ​​TransformGroup​​ - 组合转换

1.TranslateTransform (平移)

<Button Content="平移按钮">
    <Button.RenderTransform>
        <TranslateTransform X="50" Y="30"/>
    </Button.RenderTransform>
</Button>

2.RotateTransform (旋转)

<Button Content="旋转按钮">
    <Button.RenderTransform>
        <RotateTransform Angle="45" CenterX="50" CenterY="50"/>
    </Button.RenderTransform>
</Button>
  • Angle: 旋转角度(0-360)
  • CenterX/CenterY: 旋转中心点坐标

3.ScaleTransform (缩放)

<Button Content="缩放按钮">
    <Button.RenderTransform>
        <ScaleTransform ScaleX="1.5" ScaleY="0.8"/>
    </Button.RenderTransform>
</Button>
  • ScaleX: 水平缩放比例(1.0为原始大小)
  • ScaleY: 垂直缩放比例
  • CenterX/CenterY: 缩放中心点(可选)

4.SkewTransform (倾斜)

<Button Content="倾斜按钮">
    <Button.RenderTransform>
        <SkewTransform AngleX="20" AngleY="10"/>
    </Button.RenderTransform>
</Button>

5.TransformGroup (组合转换)

<Button Content="组合转换">
    <Button.RenderTransform>
        <TransformGroup>
            <RotateTransform Angle="30"/>
            <ScaleTransform ScaleX="1.2" ScaleY="1.2"/>
            <TranslateTransform X="20" Y="10"/>
        </TransformGroup>
    </Button.RenderTransform>
</Button>

6.布局转换 vs 渲染转换

  • ​LayoutTransform​​: 在布局阶段应用,影响布局计算
  • ​​RenderTransform​​: 在渲染阶段应用,不影响布局

十四.画刷

WPF提供了多种画刷类型:

  • ​​SolidColorBrush​​ - 纯色画刷
  • ​​LinearGradientBrush​​ - 线性渐变画刷
  • ​​RadialGradientBrush​​ - 径向渐变画刷
  • ​​ImageBrush​​ - 图像画刷
  • ​​DrawingBrush​​ - 绘图画刷
  • ​​VisualBrush​​ - 可视化元素画刷

1.SolidColorBrush (纯色画刷)

<Rectangle Width="100" Height="50">
    <Rectangle.Fill>
        <SolidColorBrush Color="Blue"/>
    </Rectangle.Fill>
</Rectangle>

<!-- 简写形式 -->
<Rectangle Width="100" Height="50" Fill="Red"/>

2.LinearGradientBrush (线性渐变画刷)

<Rectangle Width="100" Height="50">
    <Rectangle.Fill>
        <LinearGradientBrush StartPoint="0,0" EndPoint="1,1">
            <GradientStop Color="Yellow" Offset="0.0"/>
            <GradientStop Color="Red" Offset="0.5"/>
            <GradientStop Color="Blue" Offset="1.0"/>
        </LinearGradientBrush>
    </Rectangle.Fill>
</Rectangle>

StartPoint/EndPoint: 定义渐变方向(0,0到1,1的坐标系) GradientStop: 定义渐变的关键点

  • Color: 颜色值
  • Offset: 位置(0.0到1.0)

3.RadialGradientBrush (径向渐变画刷)

<Rectangle Width="100" Height="50">
    <Rectangle.Fill>
        <RadialGradientBrush GradientOrigin="0.5,0.5" Center="0.5,0.5" RadiusX="0.5" RadiusY="0.5">
            <GradientStop Color="White" Offset="0"/>
            <GradientStop Color="Blue" Offset="1"/>
        </RadialGradientBrush>
    </Rectangle.Fill>
</Rectangle>

GradientOrigin: 渐变起点 Center: 渐变中心点 RadiusX/RadiusY: 渐变半径 同样使用GradientStop定义颜色变化

4.ImageBrush (图像画刷)

<Rectangle Width="200" Height="100">
    <Rectangle.Fill>
        <ImageBrush ImageSource="https://www.diandiandidi.club/favicon.ico" Stretch="UniformToFill"/>
    </Rectangle.Fill>
</Rectangle>

ImageSource: 图像路径 Stretch: 填充模式:

  • None: 原始大小
  • Fill: 拉伸填充
  • Uniform: 等比例缩放
  • UniformToFill: 等比例填充(可能裁剪)

5.DrawingBrush (绘图画刷)

<Rectangle Width="100" Height="50">
    <Rectangle.Fill>
        <DrawingBrush>
            <DrawingBrush.Drawing>
                <GeometryDrawing Brush="LightBlue">
                    <GeometryDrawing.Pen>
                        <Pen Brush="Blue" Thickness="1"/>
                    </GeometryDrawing.Pen>
                    <GeometryDrawing.Geometry>
                        <RectangleGeometry Rect="0,0,100,50"/>
                    </GeometryDrawing.Geometry>
                </GeometryDrawing>
            </DrawingBrush.Drawing>
        </DrawingBrush>
    </Rectangle.Fill>
</Rectangle>

  • 使用Drawing对象定义复杂图案
  • 适合创建自定义纹理和重复图案

6.VisualBrush (可视化元素画刷)

<StackPanel>
    <StackPanel x:Name="sourcePanel" Background="LightGray">
        <Button Content="示例按钮"/>
        <Ellipse Width="50" Height="30" Fill="Green"/>
    </StackPanel>
    
    <Rectangle Width="200" Height="100" Margin="0,10,0,0">
        <Rectangle.Fill>
            <VisualBrush Visual="{Binding ElementName=sourcePanel}"/>
        </Rectangle.Fill>
    </Rectangle>
</StackPanel>

  • 可以将任何可视化元素作为画刷内容
  • 适合创建反射效果、放大镜等效果

7.画刷资源

<Window.Resources>
    <LinearGradientBrush x:Key="myGradient" StartPoint="0,0" EndPoint="1,1">
        <GradientStop Color="Yellow" Offset="0.0"/>
        <GradientStop Color="Orange" Offset="1.0"/>
    </LinearGradientBrush>
</Window.Resources>

<Grid Background="{StaticResource myGradient}">
    <!-- 内容 -->
</Grid>

8.画刷转换

<Rectangle Width="100" Height="50">
    <Rectangle.Fill>
        <LinearGradientBrush StartPoint="0,0" EndPoint="1,0">
            <LinearGradientBrush.RelativeTransform>
                <RotateTransform Angle="45" CenterX="0.5" CenterY="0.5"/>
            </LinearGradientBrush.RelativeTransform>
            <GradientStop Color="Red" Offset="0"/>
            <GradientStop Color="Yellow" Offset="1"/>
        </LinearGradientBrush>
    </Rectangle.Fill>
</Rectangle>

9.不透明度

<Rectangle Width="100" Height="50">
    <Rectangle.Fill>
        <SolidColorBrush Color="Blue" Opacity="0.5"/>
    </Rectangle.Fill>
</Rectangle>

十五.特效

WPF特效是基于像素的视觉效果,可以应用于任何UI元素,为应用程序添加专业级的视觉效果而无需编写复杂代码。 WPF提供以下内置特效:

  • ​​BlurEffect​​ - 模糊效果
  • ​​DropShadowEffect​​ - 投影效果
  • ​​ShaderEffect​​ - 自定义着色器效果
  • ​​BitmapEffect (已过时)​​ - 早期特效(不推荐使用)

1.BlurEffect (模糊效果)

<Button Content="模糊按钮" Width="100" Height="30">
    <Button.Effect>
        <BlurEffect Radius="2" KernelType="Gaussian"/>
    </Button.Effect>
</Button>

​​Radius​​: 模糊半径(0-20),值越大越模糊 ​​KernelType​​: 模糊内核类型

  • Box - 简单快速但质量较低
  • Gaussian - 高斯模糊(质量更好)

2.DropShadowEffect (投影效果)

<Button Content="投影按钮" Width="100" Height="30">
    <Button.Effect>
        <DropShadowEffect 
            Color="Black"
            Direction="315"
            ShadowDepth="10"
            Opacity="0.7"
            BlurRadius="5"/>
    </Button.Effect>
</Button>

​Color​​: 阴影颜色(默认Black) ​​Direction​​: 阴影方向(0-360度) ​​ShadowDepth​​: 阴影距离(默认5) ​​Opacity​​: 透明度(0.0-1.0) ​​BlurRadius​​: 模糊半径(默认5) ​​RenderingBias​​: 性能与质量选择

  • Performance - 性能优先
  • Quality - 质量优先

3.悬浮效果

<Button Content="悬停效果">
    <Button.Style>
        <Style TargetType="Button">
            <Setter Property="Effect">
                <Setter.Value>
                    <DropShadowEffect BlurRadius="5" ShadowDepth="2" Opacity="0.5"/>
                </Setter.Value>
            </Setter>
            <Style.Triggers>
                <Trigger Property="IsMouseOver" Value="True">
                    <Setter Property="Effect">
                        <Setter.Value>
                            <DropShadowEffect BlurRadius="15" ShadowDepth="10" Opacity="0.8"/>
                        </Setter.Value>
                    </Setter>
                </Trigger>
            </Style.Triggers>
        </Style>
    </Button.Style>
</Button>

4.聚焦高亮

<TextBox>
    <TextBox.Style>
        <Style TargetType="TextBox">
            <Style.Triggers>
                <Trigger Property="IsFocused" Value="True">
                    <Setter Property="Effect">
                        <Setter.Value>
                            <DropShadowEffect Color="DodgerBlue" BlurRadius="10" ShadowDepth="0"/>
                        </Setter.Value>
                    </Setter>
                </Trigger>
            </Style.Triggers>
        </Style>
    </TextBox.Style>
</TextBox>

十六.动画

WPF动画系统特点

  • ​​基于时间线​​:通过时间线控制属性变化
  • ​​声明式编程​​:可在XAML中直接定义动画
  • ​​硬件加速​​:利用GPU提高性能
  • ​​丰富的动画类型​​:支持多种属性动画

核心动画类型

  • ​​基本动画​​:DoubleAnimation, ColorAnimation, PointAnimation等
  • ​​关键帧动画​​:DoubleAnimationUsingKeyFrames, ColorAnimationUsingKeyFrames等
  • ​​路径动画​​:DoubleAnimationUsingPath, PointAnimationUsingPath
  • ​​自定义动画​​:继承AnimationTimeline

简单案例 鼠标放上去后,0.2秒内宽度从30变成40

<Button x:Name="myButton" Content="动画按钮" Width="100" Height="30">
    <Button.Triggers>
        <EventTrigger RoutedEvent="Button.MouseEnter">
            <BeginStoryboard>
                <Storyboard>
                    <DoubleAnimation
                        Storyboard.TargetName="myButton"
                        Storyboard.TargetProperty="Height"
                        From="30" To="40" Duration="0:0:0.2"/>
                </Storyboard>
            </BeginStoryboard>
        </EventTrigger>
    </Button.Triggers>
</Button>

1.基础动画

1.1 属性动画 (Property Animation)

适用场景:

  • 简单属性变化(如宽度、高度、透明度等)
  • 不需要复杂时间控制的动画

常用类型:

  • DoubleAnimation - 用于双精度值属性(Width/Height/Opacity等)
  • ColorAnimation - 用于颜色属性(Background/Foreground等)
  • PointAnimation - 用于点属性(如图形位置)
  • ThicknessAnimation - 用于边距属性(Margin/Padding)
<!-- 宽度动画 -->
<DoubleAnimation
    Storyboard.TargetProperty="Width"
    From="100" To="200" Duration="0:0:1"/>

<!-- 颜色动画 -->
<ColorAnimation
    Storyboard.TargetProperty="(Panel.Background).(SolidColorBrush.Color)"
    From="Red" To="Blue" Duration="0:0:2"/>

2.关键帧动画

<DoubleAnimationUsingKeyFrames Storyboard.TargetProperty="Width">
    <!-- 线性变化 -->
    <LinearDoubleKeyFrame Value="100" KeyTime="0:0:0"/>
    <!-- 突然变化 -->
    <DiscreteDoubleKeyFrame Value="120" KeyTime="0:0:1"/>
    <!-- 平滑变化 -->
    <SplineDoubleKeyFrame Value="200" KeyTime="0:0:2" 
                         KeySpline="0.5,0 0.5,1"/>
</DoubleAnimationUsingKeyFrames>

3.路径动画

<Canvas>
    <!-- 定义路径 -->
    <Path x:Name="motionPath" Data="M 10,100 C 35,0 135,0 160,100" Stroke="Black"/>
    
    <!-- 动画元素 -->
    <Rectangle Width="20" Height="20" Fill="Red">
        <Rectangle.RenderTransform>
            <TranslateTransform x:Name="rectTransform"/>
        </Rectangle.RenderTransform>
    </Rectangle>
    
    <!-- 路径动画 -->
    <DoubleAnimationUsingPath
        Storyboard.TargetName="rectTransform"
        Storyboard.TargetProperty="X"
        PathGeometry="{Binding Data, ElementName=motionPath}"
        Duration="0:0:3" Source="X"/>
</Canvas>

4.并行动画

<Storyboard>
    <ParallelTimeline>
        <DoubleAnimation Storyboard.TargetProperty="Width" To="200" Duration="0:0:1"/>
        <ColorAnimation Storyboard.TargetProperty="Background.Color" To="Blue" Duration="0:0:1"/>
    </ParallelTimeline>
</Storyboard>

5.顺序动画

<Storyboard>
    <SequenceTimeline>
        <DoubleAnimation Storyboard.TargetProperty="Opacity" To="0" Duration="0:0:0.5"/>
        <DoubleAnimation Storyboard.TargetProperty="Width" To="0" Duration="0:0:0.5"/>
    </SequenceTimeline>
</Storyboard>

十七.行为

1.什么是Behavior?

在 WPF (Windows Presentation Foundation) 中,​​Behavior​​ 是一种强大的设计模式,允许开发者通过附加属性(Attached Properties)将可重用的交互逻辑或功能封装到 UI 元素(如控件)中,而无需修改控件本身的代码或继承子类。Behavior 的核心思想是​​通过附加而非继承​​来扩展控件的功能。

1.1 Behavior 的核心概念​

  • 属于 Microsoft.Xaml.Behaviors 库​:Behavior 最初是 System.Windows.Interactivity 命名空间的一部分(来自 Blend SDK),后来迁移到独立的库 Microsoft.Xaml.Behaviors.Wpf。需通过 NuGet 安装此包。
  • 基于附加属性(Attached Properties)​:Behavior 通过附加属性将自身绑定到控件,从而监听事件、修改属性或调用方法。
  • 无需继承或模板重写​:例如:为按钮添加鼠标悬停动画,无需创建自定义按钮类。

1.2 ​Behavior 的组成​

Behavior 基类​​ 泛型类(T 是目标控件的类型),需重写以下方法: OnAttached(): Behavior 附加到控件时调用。 OnDetaching(): Behavior 从控件移除时调用。

​​触发器和动作​​ ​​Trigger​​(触发器):监听条件(如点击、数据变化),触发时执行关联的 Action。 ​​Action​​(动作):定义具体的响应行为(如播放动画、导航页面)。

2.示例:按钮动画

public class ScaleButtonBehavior : Behavior<Button>
{
    protected override void OnAttached()
    {
        base.OnAttached();
        AssociatedObject.Click += OnButtonClick;
    }

    private void OnButtonClick(object sender, RoutedEventArgs e)
    {
        var scaleTransform = new ScaleTransform(1, 1);
        AssociatedObject.RenderTransform = scaleTransform;

        var animation = new DoubleAnimation(1.2, TimeSpan.FromSeconds(0.3));
        scaleTransform.BeginAnimation(ScaleTransform.ScaleXProperty, animation);
        scaleTransform.BeginAnimation(ScaleTransform.ScaleYProperty, animation);
    }

    protected override void OnDetaching()
    {
        AssociatedObject.Click -= OnButtonClick;
        base.OnDetaching();
    }
}
<Window xmlns:i="http://schemas.microsoft.com/xaml/behaviors">
    <Button Content="Click Me">
        <i:Interaction.Behaviors>
            <local:ScaleButtonBehavior />
        </i:Interaction.Behaviors>
    </Button>
</Window>

十八.导航

在 WPF 中,​​导航(Navigation)​​ 允许应用程序在不同的页面(Page)之间切换,类似于 Web 浏览器中的页面跳转。WPF 提供了内置的导航框架,支持前进、后退、页面缓存等功能,适用于需要多页面的应用程序(如向导、设置窗口或文档查看器)。

1.WPF导航的核心组件​

1.1 Frame 控件​

作用​​:作为导航容器,承载并切换不同的 Page。 ​​关键属性​​:

  • Source:指定初始页面的 URI。
  • NavigationUIVisibility:控制是否显示导航工具栏(前进/后退按钮)。
  • JournalOwnership:决定是否保留导航历史记录(默认 OwnsJournal)。

1.2 Page 类​

作用​​:表示可导航的页面,类似于 Window,但专为导航设计。 ​​关键特性​​:

  • 支持标题(Title)、窗口宽度/高度(WindowWidth、WindowHeight)。
  • 可通过 NavigationService 实现编程导航。

作用​​:提供导航的编程控制(如跳转、前进、后退)。 ​​常用方法​​:

  • Navigate():跳转到指定页面。
  • GoBack() / GoForward():导航历史记录的前进/后退。
  • StopLoading():取消导航。

2.实现导航的步骤​

2.1 定义 Page

创建多个页面(如 Page1.xaml 和 Page2.xaml):

<!-- Page1.xaml -->
<Page x:Class="WpfApp.Page1"
      xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
      xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
      Title="Page 1">
    <StackPanel>
        <TextBlock Text="This is Page 1"/>
        <Button Content="Go to Page 2" Click="NavigateToPage2"/>
    </StackPanel>
</Page>
// Page1.xaml.cs
private void NavigateToPage2(object sender, RoutedEventArgs e)
{
    // 通过 NavigationService 导航
    this.NavigationService?.Navigate(new Uri("Page2.xaml", UriKind.Relative));
}

2.2 使用 Frame 承载导航​

在 MainWindow.xaml 中添加 Frame:

<Window x:Class="WpfApp.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="WPF Navigation" Height="300" Width="400">
    <Frame x:Name="MainFrame" Source="Page1.xaml" NavigationUIVisibility="Visible"/>
</Window>

3.导航的常见操作​

3.1 编程导航​

通过 NavigationService 或 Frame 直接控制:

// 跳转到 Page2
MainFrame.Navigate(new Uri("Page2.xaml", UriKind.Relative));

// 前进/后退
if (MainFrame.CanGoBack) 
    MainFrame.GoBack();

if (MainFrame.CanGoForward) 
    MainFrame.GoForward();

3.2 传递参数​

使用 Navigate 方法传递对象:

// 传递参数
MainFrame.Navigate(new Page2(), "Hello from Page1!");

// 在 Page2 中接收参数
protected override void OnNavigatedTo(NavigationEventArgs e)
{
    if (e.ExtraData is string message)
    {
        MessageBox.Show(message); // 输出 "Hello from Page1!"
    }
}

3.3 拦截导航事件​

  • ​​Navigating​​:导航开始前触发(可取消)。
  • ​​Navigated​​:导航完成后触发。
MainFrame.Navigating += (sender, e) => 
{
    if (e.Uri.ToString().Contains("Page2"))
    {
        e.Cancel = true; // 阻止跳转到 Page2
    }
};

4.导航的进阶用法​

4.1 页面缓存​

默认情况下,WPF 会缓存已访问的页面。可通过 Page 的 KeepAlive 属性控制:

<Page KeepAlive="False" ... />

4.2 自定义导航工具栏​

隐藏默认工具栏,自定义按钮:

<Frame NavigationUIVisibility="Hidden">
    <Frame.Template>
        <ControlTemplate>
            <StackPanel>
                <StackPanel Orientation="Horizontal">
                    <Button Content="Back" Command="{x:Static NavigationCommands.BrowseBack}"/>
                    <Button Content="Forward" Command="{x:Static NavigationCommands.BrowseForward}"/>
                </StackPanel>
                <ContentPresenter/> <!-- 显示当前 Page -->
            </StackPanel>
        </ControlTemplate>
    </Frame.Template>
</Frame>