目录
用户通过窗口与 Windows Presentation Foundation (WPF) 应用程序交互。 窗口的主要用途是托管使数据可视化并使用户能够与数据交互的内容。 WPF 应用程序使用 Window
类提供自己的窗口。 本文先介绍
Window,然后讲述在应用程序中创建和管理窗口的基础知识。
本文使用从 C# 项目生成的 XAML。 如果使用 Visual Basic,则 XAML 看上去可能有不同。 这些差异通常出现在 x:Class
属性值上。 C# 包括项目的根命名空间,而 Visual Basic 不包括。
C# 的项目模板创建了一个 App
类型,包含在 app.xaml 文件中。 在 Visual Basic 中,该类型名为 Application
,该文件名为 Application.xaml
。
1、窗口类
在 WPF 中,窗口由用于执行以下操作的
Window 类封装:
- 显示窗口。
- 配置窗口的大小、位置和外观。
- 托管特定于应用程序的内容。
- 管理窗口的生存期。
下图展示了窗口的构成部分:
窗口分为两个区域:非工作区和工作区。
窗口的非工作区由 WPF实现,它包括大多数窗口所共有的窗口部分,包括:
- 标题栏 (1-5)。
- 图标 (1)。
- 标题 (2)。
- 最小化 (3)、最大化 (4) 和关闭 (5) 按钮。
- 包含菜单项的系统菜单 (6)。 单击图标 (1) 时出现。
- 边框 (7)。
窗口的工作区是窗口的非工作区内部的区域,由开发人员用于添加特定于应用程序的内容,例如菜单栏、工具栏和控件。
- 工作区 (8)。
- 大小调整手柄 (9)。 这是添加到工作区 (8) 的控件。
2、实现窗口
典型窗口的实现既包括外观又包括行为,外观定义用户看到的窗口的样子,行为定义用户与之交互时窗口的运行方式。 在 WPF 中,可以使用代码或 XAML 标记实现窗口的外观和行为。
但在一般情况下,窗口的外观使用 XAML 标记实现,行为使用代码隐藏实现,如以下示例所示。
<Window x:Class="WindowsOverview.Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:WindowsOverview"
>
<!-- Client area containing the content of the window -->
</Window>
下面的代码是 XAML 的代码隐藏。
using System.Windows;
namespace WindowsOverview
{
public partial class Window1 : Window
{
public Window1()
{
InitializeComponent();
}
}
}
若要使 XAML 标记文件和代码隐藏文件配合工作,需要满足以下要求:
-
在标记中,
Window
元素必须包含x:Class
属性。 生成应用程序时,标记文件中存在x:Class
会使 Microsoft 生成引擎 (MSBuild) 生成派生自
Window 的partial
类,其名称由x:Class
属性指定。 这要求为 XAML 架构 (xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
) 添加 XAML 命名空间声明。 生成的partial
类实现InitializeComponent
方法,注册事件和设置在标记中实现的属性时将调用此方法。 -
在代码隐藏中,类必须是
partial
类、名称必须是标记中x:Class
属性指定的相同名称,并且它必须派生自
Window。 这样,代码隐藏文件就与应用程序生成时为标记文件生成的partial
类相关联。 -
在代码隐藏中,
Window 类必须实现调用InitializeComponent
方法的构造函数。InitializeComponent
由标记文件已生成的partial
类实现,用以注册事件并设置标记中定义的属性。
使用 Visual Studio 将新的 Window
添加到项目时,
Window 通过同时使用标记和代码隐藏实现,并且包括必要的配置来创建此处所述的标记文件和代码隐藏文件之间的关联。
进行了此配置后,可以专注于在 XAML 标记中定义窗口的外观,并可在代码隐藏中实现窗口的行为。 以下示例显示了一个窗口,该窗口中的一个按钮定义了
Click 事件的事件处理程序。 这是在 XAML 中实现的,处理程序是在代码隐藏中实现的。
<Window x:Class="WindowsOverview.Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:WindowsOverview"
>
<!-- Client area containing the content of the window -->
<Button Click="Button_Click">Click This Button</Button>
</Window>
下面的代码是 XAML 的代码隐藏。
using System.Windows;
namespace WindowsOverview
{
public partial class Window1 : Window
{
public Window1()
{
InitializeComponent();
}
private void Button_Click(object sender, RoutedEventArgs e)
{
MessageBox.Show("Button was clicked.");
}
}
}
2.1 为 MSBuild 配置窗口
实现窗口的方式决定为 MSBuild 配置窗口的方式。 对于使用 XAML 标记和代码隐藏定义的窗口:
- XAML 标记文件配置为 MSBuild
Page
项。 - 代码隐藏文件配置为 MSBuild
Compile
项。
.NET SDK 项目会自动导入正确的 Page
和 Compile
项,无需对其进行声明。 如果为 WPF 配置了项目,则会将 XAML 标记文件自动导入为 Page
,并将相应的代码隐藏文件导入为 Compile
。
MSBuild 项目不会自动导入类型,你必须自行声明它们:
<Project>
...
<Page Include="MarkupAndCodeBehindWindow.xaml" />
<Compile Include=" MarkupAndCodeBehindWindow.xaml.cs" />
...
</Project>
3、窗口生存期
与所有类一样,窗口也有生存期,开始于首次实例化窗口,在这之后将打开、激活/停用直至最终关闭窗口。
3.1 打开窗口
若要打开窗口,首先要创建窗口实例,下面的示例演示此操作:
using System.Windows;
namespace WindowsOverview
{
public partial class App : Application
{
private void Application_Startup(object sender, StartupEventArgs e)
{
// Create the window
Window1 window = new Window1();
// Open the window
window.Show();
}
}
}
在本示例中,Window1
在应用程序启动时实例化,此过程在引发
Startup 事件时发生。
实例化窗口后,对其的引用将自动添加到由
Application 对象管理的窗口列表
。
Application 会将要实例化的第一个窗口自动设置为主应用程序窗口
。
最后通过调用
Show 方法打开窗口,如以下图像所示:
通过调用
Show 打开的窗口是无模式窗口,应用程序不会阻止用户与该应用程序中的其他窗口交互。 通过
ShowDialog 打开窗口时,会将窗口打开为模式,并限制用户与该窗口交互。
调用
Show时,窗口先执行初始化工作,然后显示窗口以建立让窗口可以接收用户输入的基础结构。 初始化窗口时,将引发
SourceInitialized事件并显示窗口。
启动窗口
上一个示例使用了 Startup
事件来运行显示初始应用程序窗口的代码。 作为快捷方式,请改用
StartupUri 来指定应用程序中 XAML 文件的路径。 应用程序将自动创建并显示由该属性指定的窗口。
<Application x:Class="WindowsOverview.App"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:WindowsOverview"
StartupUri="ClippedWindow.xaml">
<Application.Resources>
</Application.Resources>
</Application>
窗口所有权
使用 Show
方法打开的窗口与创建它的窗口不具有隐式关系。 用户可以与其中任意一个窗口独立交互,这意味着这两个窗口都可以执行以下操作:
- 覆盖另一个窗口(除非其中一个窗口的 Topmost
属性设置为true
)。 - 在不影响另一个窗口的情况下最小化、最大化和还原。
某些窗口要求与打开它们的窗口保持某种关系。 例如,集成开发环境 (IDE) 应用程序可能打开属性窗口和工具窗口,这些窗口的典型行为是覆盖创建它们的窗口。 此外,此类窗口应始终与创建它们的窗口一起关闭、最小化、最大化和还原。 可以通过让一个窗口拥有另一个窗口来建立这种关系,通过使用对所有者窗口的引用设置被拥有窗口的
Owner 属性来实现。 这在下面的示例中显示。
private void Button_Click(object sender, RoutedEventArgs e)
{
// Create a window and make the current window its owner
var ownedWindow = new ChildWindow1();
ownedWindow.Owner = this;
ownedWindow.Show();
}
建立所有权后:
- 被拥有的窗口可以通过检查其
Owner 属性的值来引用它的所有者窗口。 - 所有者窗口可以通过检查其
OwnedWindows 属性的值来发现它拥有的所有窗口。
3.2 窗口激活
第一次打开窗口时,它即成为活动窗口。 活动窗口是当前捕获用户输入(例如击键和鼠标单击)的窗口。 当窗口处于活动状态时,它会引发
Activated 事件。
第一次打开窗口时,只有当引发
Activated 后才会引发
Loaded 和
ContentRendered 事件