户通过窗口与 Windows Presentation Foundation (WPF) 独立应用程序进行交互。窗口的主要用途是承载可视化数据并使用户可以与数据进行交互的内容。独立 WPF 应用程序使用 Window 类来提供它们自己的窗口
窗口分为两个区域:非工作区和工作区。
窗口的非工作区由 WPF 实现,它包括大多数窗口所共有的窗口部分,其中包括:
边框。
标题栏。
图标。
“最小化”、“最大化”和“还原”按钮。
“关闭”按钮。
“系统”菜单,其中包含允许用户最小化、最大化、还原、移动和关闭窗口以及调整窗口大小的菜单项。
窗口的工作区是窗口的非工作区内部的区域,开发人员使用它来添加应用程序特定的内容,如菜单栏、工具栏和控件。
在 WPF 中,窗口通过 Window 类进行封装,使用该类可以执行下面的操作:
显示窗口。
配置窗口的大小、位置和外观。
承载应用程序特定的内容。
管理窗口的生存期。
本节包含下列子节。
若要打开窗口,首先应创建一个窗口实例,下面的示例演示此操作。
在此示例中,在应用程序启动时(在引发 Startup 事件时发生),MarkupAndCodeBehindWindow 进行实例化。
在实例化窗口时,指向该窗口的引用会自动添加到由 Application 对象管理的窗口列表中(请参见 Application.Windows)。另外,默认情况下,Application 会将实例化的第一个窗口设置为主应用程序窗口(请参见 Application.MainWindow)。
最后,通过调用 Show 方法打开窗口;结果如下图所示。
通过调用 Show 打开的窗口是无模式窗口,这意味着应用程序所运行的模式允许用户在同一个应用程序中激活其他窗口。
当调用 Show 时,在显示窗口以建立让窗口可以接收用户输入的基础结构之前,窗口会执行初始化工作。当初始化窗口时,将引发 SourceInitialized 事件并显示窗口。
作为一种快捷方式,可以设置 StartupUri 以指定在应用程序启动时自动打开的第一个窗口。
当应用程序启动时,StartupUri 的值所指定的窗口会无模式地打开;在内部,则通过调用 Show 方法来打开窗口。
使用 Show 方法打开的窗口与创建它的窗口之间没有隐式关系;用户可以与这两个窗口分别进行独立的交互,这意味着这两个窗口都可以执行下面的操作:
覆盖另一个窗口(除非其中一个窗口的 Topmost 属性设置为 true)。
在不影响另一个窗口的情况下,最小化、最大化和还原一个窗口。
某些窗口要求与打开它们的窗口之间保持某种关系。例如,集成开发环境 (IDE) 应用程序可能会打开属性窗口和工具窗口,而这些窗口的典型行为是覆盖创建它们的窗口。此外,此类窗口应始终与创建它们的窗口协调一致地进行关闭、最小化、最大化和还原。可以通过让一个窗口拥有另一个窗口来建立这种关系,也可以通过使用对所有者窗口的引用来设置附属窗口的 Owner 属性,以建立这种关系。这将在下面的示例中显示。
// Create a window and make this window its owner Window ownedWindow = new Window(); ownedWindow.Owner = this; ownedWindow.Show();
建立了所属权之后:
附属窗口可以通过检查 Owner 属性的值来引用它的所有者窗口。
所有者窗口可以通过检查 OwnedWindows 属性的值来发现它拥有的全部窗口。
有些情况下,不应在显示窗口时将其激活,例如 Internet Messenger 风格的应用程序的对话窗口或电子邮件应用程序的通知窗口。
如果应用程序具有不应在显示时被激活的窗口,可以在首次调用 Show 方法之前将其 ShowActivated 属性设置为 false。这样:
窗口便不会被激活。
也不会引发窗口的 Activated 事件。
当前激活的窗口保持激活状态。
但是,只要用户通过单击客户端或非客户端区域激活了窗口,窗口就会变为激活状态。在这种情况下:
窗口被激活。
引发窗口的 Activated 事件。
停用以前激活的窗口。
随后作为对用户操作的响应,如期引发窗口的 Deactivated 和 Activated 事件。
在首次打开一个窗口时,它便成为活动窗口(除非是在 ShowActivated 设置为 false 的情况下显示)。活动窗口是当前正在捕获用户输入(例如,键击和鼠标单击)的窗口。当窗口变为活动窗口时,它会引发 Activated 事件。
窗口变为活动窗口之后,用户可以在同一个应用程序中激活其他窗口,还可以激活其他应用程序。当这种情况出现时,当前的活动窗口将停用,并引发 Deactivated 事件。同样,当用户选择当前停用的窗口时,该窗口会再次变成活动窗口并引发 Activated。
处理 Activated 和 Deactivated 的一个常见原因是为了启用和禁用只有在窗口活动时才能够运行的功能。例如,某些窗口显示的交互式内容需要持续的用户输入或需要用户时刻注意,包括游戏和视频播放机。下面的示例是一个简化的视频播放机,演示如何处理 Activated 和 Deactivated 以实现此行为。
<Window xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" x:Class="SDKSample.CustomMediaPlayerWindow" Activated="window_Activated" Deactivated="window_Deactivated"> <!-- Media Player --> <MediaElement Name="mediaElement" Stretch="Fill" LoadedBehavior="Manual" Source="numbers.wmv" /> </Window>
using System; // EventArgs using System.Windows; // Window namespace SDKSample { public partial class CustomMediaPlayerWindow : Window { public CustomMediaPlayerWindow() { InitializeComponent(); } void window_Activated(object sender, EventArgs e) { // Recommence playing media if window is activated this.mediaElement.Play(); } void window_Deactivated(object sender, EventArgs e) { // Pause playing if media is being played and window is deactivated this.mediaElement.Pause(); } } }
当用户关闭窗口时,窗口的生命便开始走向终结。可以使用非工作区中的元素来关闭窗口,这些元素包括:
“系统”菜单的“关闭”项。
按 Alt + F4。
按“关闭”按钮。
可以为工作区提供关闭窗口的附加机制,其中比较常用的包括:
“文件”菜单中的“退出”项,通常用于主应用程序窗口。
“文件”菜单中的“关闭”项,通常出现在辅助应用程序窗口中。
“取消”按钮,通常出现在模式对话框中。
“关闭”按钮,通常出现在无模式对话框中。
若要响应这些自定义机制中某个机制来关闭窗口,需要调用 Close 方法。下面的示例实现通过选择“文件”菜单上的“退出”来关闭窗口的功能。
<Window xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" x:Class="SDKSample.WindowWithFileExit"> <Menu> <MenuItem Header="_File"> <MenuItem Header="E_xit" Click="fileExitMenuItem_Click" /> </MenuItem> </Menu> </Window>
using System.Windows; // window, RoutedEventArgs namespace SDKSample { public partial class WindowWithFileExit : System.Windows.Window { public WindowWithFileExit() { InitializeComponent(); } void fileExitMenuItem_Click(object sender, RoutedEventArgs e) { // Close this window this.Close(); } } }
当窗口关闭时,它会引发两个事件:Closing 和 Closed。
Closing 在窗口关闭之前引发,它提供一种机制,可以通过这种机制来阻止窗口关闭。阻止窗口关闭的一个常见原因是窗口内容包含了已修改数据。在这种情况下,可以处理 Closing 事件来确定数据是否已更新,如果已更新,则询问用户是继续关闭窗口而不保存数据,还是取消窗口关闭。下面的示例显示处理 Closing 的关键方面
当窗口打开时,窗口在相对于桌面的 x 和 y 维度有一个位置。可以通过分别检查 Left 和 Top 属性来确定此位置。可以设置这些属性以更改窗口的位置。
通过将 WindowStartupLocation 属性设置为下面的 WindowStartupLocation 枚举值之一,还可以指定 Window 第一次出现时的初始位置:
如果将起始位置指定为 Manual,并且未设置 Left 和 Top 属性,则 Window 将向 Windows 请求显示的位置。
除了具有 x 和 y 位置之外,窗口还在 z 维度中具有位置,该位置确定窗口相对于其他窗口的垂直位置。此位置称作窗口的 z 顺序,有两种 z 顺序:正常 z 顺序和最顶层 z 顺序。在正常 z 顺序中,窗口的位置取决于窗口当前是否活动。默认情况下,窗口位于正常 z 顺序中。在最顶层 z 顺序中,窗口的位置也取决于窗口当前是否活动。此外,在最顶层 z 顺序中的窗口总是位于正常 z 顺序中的窗口之上。通过将窗口的 Topmost 属性设置为 true 可以使窗口位于最顶层 z 顺序中。
在每个 z 顺序中,当前活动的窗口都会显示在同一 z 顺序中的所有其他窗口之上。
除了具有桌面位置以外,窗口还有一定的大小,窗口大小由多个属性确定,包括各种宽度和高度属性以及 SizeToContent。
MinWidth、Width 和 MaxWidth 用于管理窗口在生存期中可以具有的宽度的范围,其配置如下面的示例所示。
窗口高度由 MinHeight、Height 和 MaxHeight 管理,其设置如下面的示例所示。
因为各个宽度值和高度值各自指定了一个范围,所以可调整大小的窗口的宽度和高度可以是相应维度的指定范围内的任何值。若要检测窗口的当前宽度和高度,请分别检查 ActualWidth 和 ActualHeight。
如果您想让窗口的宽度和高度适应窗口内容的大小,则可以使用 SizeToContent 属性,该属性具有下面的值:
Manual.不起任何作用(默认)。
WidthAndHeight.可以适应与内容宽度和高度,这与将 MinHeight 和 MaxHeight 设置为内容的高度并将 MinWidth 和 MaxWidth 设置为内容的宽度具有相同的效果。
下面的示例演示一个窗口自动调整大小垂直和水平地适应其内容,,那么,当首次显示。
下面的示例演示如何在代码中设置 SizeToContent 属性指定调整窗口大小以适合其内容。
// Manually alter window height and width this.SizeToContent = SizeToContent.Manual; // Automatically resize width relative to content this.SizeToContent = SizeToContent.Width; // Automatically resize height relative to content this.SizeToContent = SizeToContent.Height; // Automatically resize height and width relative to content this.SizeToContent = SizeToContent.WidthAndHeight;
实质上,窗口的各种大小属性可以结合使用,以定义可调整大小的窗口的宽度和高度范围。为了确保保持有效的范围,Window 会使用下面的优先级顺序来计算大小属性的值。
对于高度属性:
对于宽度属性:
优先级顺序还可以确定窗口在最大化时的大小;此时的窗口大小使用 WindowState 属性管理。
在可调整大小的窗口的生存期内,窗口可以有三种状态:正常、最小化和最大化。处于正常状态的窗口是窗口的默认状态。处于此状态的窗口如果是可调整大小的,则允许用户使用大小调整手柄或边框来移动窗口或调整窗口大小。
如果 ShowInTaskbar 设置为 true,则处于最小化状态的窗口会折叠到任务栏按钮;否则,窗口会折叠到可能的最小大小并重新定位到桌面的左下角。尽管不在任务栏中显示的最小化窗口可以在桌面上四处拖动,但是不能使用边框或大小调整手柄来调整上述两种最小化窗口的大小。
处于最大化状态的窗口会扩展到可能达到的最大大小,而最大大小只能与 MaxWidth、MaxHeight 和 SizeToContent 属性规定的大小相同。与最小化窗口一样,最大化窗口的大小也无法通过使用大小调整手柄或拖动边框来调整。
可以通过设置 WindowState 属性来配置窗口的状态,该属性可以取以下 WindowState 枚举值之一:
下面的示例说明如何创建在打开时最大化显示的窗口。
通常,应设置 WindowState 以配置窗口的初始状态。一旦显示了可调整大小的窗口,用户便可以按窗口的标题栏上的最小化、最大化和还原按钮来更改窗口状态。
通过向窗口工作区添加窗口特定内容(如按钮、标签和文本框),可以更改窗口工作区的外观。为了配置非工作区,Window 提供了多个属性,包括设置窗口图标的 Icon 和设置窗口标题的 Title。
还可以通过配置窗口的大小调整模式、窗口样式,以及窗口是否显示为桌面任务栏中的按钮,来更改非工作区边框的外观和行为。
本节包含下列子节。
根据 WindowStyle 属性,您可以控制用户如何(以及是否可以)调整窗口的大小。窗口样式的选择将影响用户是否可以通过用鼠标拖动边框来调整窗口的大小,非工作区是否显示“最小化”、“最大化”和“调整大小”按钮,以及如果显示这些按钮是否启用它们。
可以通过设置 ResizeMode 属性来配置窗口调整大小的方式,该属性可以取以下 ResizeMode 枚举值之一:
和 WindowStyle 相同,窗口的大小调整模式在其生存期内不能更改,这意味着您很可能会通过 XAML 标记设置该模式。
从窗口的非工作区公开的边框适合大多数应用程序。但是,在有些情况下,可能需要使用不同类型的边框,或根本不需要边框,这要取决于窗口的类型。
若要控制窗口的边框的类型,请将窗口的 WindowStyle 属性设置为以下 WindowStyle 枚举值之一:
下图显示了这些窗口样式的效果。
可以使用 XAML 标记或代码设置 WindowStyle;因为窗口样式不能在窗口的生存期内更改,所以您很可能会使用 XAML 标记对其进行配置。
在另外一些情况下, WindowStyle 允许使用的边框样式不足以满足需要。例如,您可能希望创建一个带有非矩形边框的应用程序,如 Microsoft Windows Media Player 所使用的边框。
下图中显示的对话气泡框就是一个例子。
通过将 WindowStyle 属性设置为 None,并利用 Window 对透明度的特殊支持,可以创建此类型的窗口。