Windows(窗体)是一个容器,所有需要显示的内容都需要在window里面,用户的交互也是全部基于windows,WPF就是Windows Presentation Foundation的简写,这里面的windows可以理解为操作系统,但是未尝不可以理解成窗体(windows系统的命名可能就是基于这个考量)
基类是window,提供了以下功能
- 窗体相关功能,如标题栏、最小化、最大化、关闭按钮,以及可拖动和调整大小的边框。
- 提供一个容器来容纳指定内容,content属性来指定窗口的内容
- 控制窗体的生命周期和其他属性
<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>
using System.Windows;
namespace WindowsOverview
{
public partial class Window1 : Window
{
public Window1()
{
InitializeComponent();
}
}
}
要使 XAML 文件和对应的后台代码一起工作,需要以下条件:
在XAML标记中,Window 元素必须包含
x:Class
属性。当应用程序构建时,x:Class
属性的存在会导致 Microsoft 构建引擎(MSBuild)生成一个由 Window 派生的部分类,类名由x:Class
属性指定。这需要添加一个 XAML 模式的 XML 命名空间声明(xmlns="http://schemas.microsoft.com/winfx/2006/xaml")。生成的部分类了实现InitializeComponent
方法(一般在后台文件的构造函数中调用),该方法用于注册在XAML中实现的事件和设置它的属性。在代码隐藏中,该类必须是与标记中的
x:Class
属性指定的名称相同的部分类,并且必须派生自 Window。这使得后台代码在程序构建时能和XAML的部分类关联。在构造函数里需要调用InitializeComponent
方法
Windows属性
-
Content 属性:
-
Window
的Content
属性用于指定窗口的主要内容,可以是一个控件或一个控件的集合(例如,布局控件Grid
,StackPanel
等)。
-
-
Title 属性:
-
Title
属性用于设置窗口的标题栏文本。它显示在窗口的顶部,并通常用于描述应用程序的名称或窗口的目的。
-
-
Width 和 Height:
- 这些属性用于设置窗口的宽度和高度。它们可以在 XAML 或代码中定义。
MinWidth和 MaxWidth用于管理窗口在其生存期内可以具有的宽度范围,同样的还有Height
也可以根据内容自适应
- SizeToContent.Manual不起作用(默认值)。
- SizeToContent.Width 适应内容宽度(固定宽度,相当于将最小宽度和最大宽度都设成固定的)
- SizeToContent.Height 适应内容高度(固定)
- SizeToContent.WidthAndHeight 适应宽高(固定)
- 这些属性用于设置窗口的宽度和高度。它们可以在 XAML 或代码中定义。
<Window
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
SizeToContent="WidthAndHeight">
</Window>
-
WindowStartupLocation:
-
WindowStartupLocation
属性指定窗口首次显示时的位置。常见的值包括CenterScreen
(屏幕中央)和Manual
(使用Left
和Top
手动设置)。
同时,除了有x,y值表示位置外,窗口还有z值,表示窗口的前后
只有两种,一种是正常的,一种是最顶层(TopMost)
-
- 正常 Z 顺序(Normal Z-order):
默认情况下,所有窗口都位于正常 Z 顺序中。在这个顺序中,窗口的显示顺序取决于窗口是否处于活动状态。活动窗口通常显示在其他非活动窗口的前面。
当一个窗口被用户点击或通过代码激活时,它会在 Z 顺序中提升,并显示在其他非活动窗口的前面。 - 最顶层 Z 顺序(Topmost Z-order):
最顶层 Z 顺序中的窗口始终显示在正常 Z 顺序中的所有窗口之上,无论它们是否处于活动状态。
窗口可以通过将其 Topmost 属性设置为 true 来进入最顶层 Z 顺序。当 Topmost 属性为 true 时,该窗口始终保持在所有其他非最顶层窗口的前面,即使这些窗口被激活也是如此。
-
WindowState:
-
WindowState
属性表示窗口的状态,如Normal
、Minimized
或Maximized
。
// 最大化窗口 myWindow.WindowState = WindowState.Maximized; // 最小化窗口 myWindow.WindowState = WindowState.Minimized; // 恢复正常状态 myWindow.WindowState = WindowState.Normal;
如果ShowInTaskbar为true(默认),那么最小化会折叠到任务栏,否则只会尽量缩小
最大化和最小化之后都无法重设大小
即使窗口已经最大化和最小化,窗口的 Top、Left Width和 Height 属性的值也始终表示正常状态的值。 -
打开窗口
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();
}
}
}
所有实例化的窗口都会加到 Application.Current.Windows,并且第一个打开的窗口会被设成主窗口(如果ShutDownMode为OnMainWindowsClose,那么主窗口关闭程序会结束)
Show打开的窗口是无模式(modeless)窗口,不会阻止用户和同APP的其他窗口交互,通过ShowDialog打开窗口时,会将窗口设置为modeless,限制用户与对话框交互
调用Show时,引发SourceInitialized事件
对应的xaml文件中,通过StartupUri来指定需要初始化和显示的主窗口,效果等同于上面的
<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>
Window Ownership(窗口所有权)
窗口所有权定义了一个窗口与另一个窗口之间的父子关系。当一个窗口拥有另一个窗口时,子窗口在父窗口之前显示,并且当父窗口关闭时,所有子窗口也会自动关闭。父窗口最大化最小化时,子窗口也会跟着变动,使用所有权可以确保有关联的窗口组的显示和关闭行为的一致性。
相对应的,如果两个窗口没有父子关系,那么他们相互独立,可以自由覆盖另一个窗口(除非设置了TopMost),且最大化最小化等不影响
在 WPF 中,可以通过设置 Owner
属性来定义窗口的所有权关系。例如:
Window childWindow = new ChildWindow();
childWindow.Owner = this; // 设置当前窗口为父窗口
childWindow.Show();
父窗口可以通过OwnedWindows属性来查看子窗口
Window Activation(窗口激活)
窗口激活指的是使窗口成为当前的活动窗口,这通常意味着窗口获得焦点,并且出现在其他窗口的前面。
第一次打开窗口时,会成为活动窗口
WPF 中的窗口激活通常由用户点击或通过代码调用 Window.Activate()
方法实现。窗口激活时,会触发 Activated
事件,窗口失活时触发 Deactivated
事件。
可以通过激活窗口通知用户事件完成(如果用户正在其他窗口交互,窗口的任务栏按钮会闪烁)
// 激活窗口
myWindow.Activate();
同样的, Application.Activated和Application.Deactivated用于应用程序的激活通知
Preventing Window Activation(防止窗口激活)
有时需要防止窗口被激活,比如显示一个仅用于信息显示的窗口。
可以在Show方法前将ShowActivated属性设成False
Closing a Window(关闭窗口)
关闭窗口可以通过调用 Window.Close()
方法。关闭窗口会触发 Closing
和 Closed
事件。Closing
事件在窗口关闭之前触发,可以用于检查是否允许关闭窗口。Closed
事件在窗口关闭后触发。
窗口关闭后,就不能重新打开了
// 关闭窗口
myWindow.Close();
Cancel Window Closure(取消窗口关闭)
在 Closing
事件的事件处理程序中,可以通过设置 CancelEventArgs.Cancel
为 true
来取消窗口的关闭操作。例如,当有未保存的更改时,弹出确认对话框让用户决定是否取消关闭操作。一旦调用了Closed事件就无法阻止窗口关闭了
private void MyWindow_Closing(object sender, System.ComponentModel.CancelEventArgs e)
{
// 弹出确认对话框
var result = MessageBox.Show("Are you sure you want to close?", "Confirm", MessageBoxButton.YesNo);
if (result == MessageBoxResult.No)
{
e.Cancel = true; // 取消关闭操作
}
}
Window Lifetime Events(窗口生命周期事件)
-
SourceInitiated
:窗口初始化时触发(调用Show时)。 -
Activated
:窗口激活时触发(Show时不一定会激活)。 -
Loaded
:窗口加载完成时触发。 -
ContentRendered
窗口有Content时触发 -
Deactivated
:窗口失活时触发。(可能不会失活) -
Closing
:窗口开始关闭时触发。只有用户关闭窗口时会触发 -
Deactivated
:窗口关闭前一定会失活。 -
Closed
:窗口关闭后触发。
[图片上传失败...(image-3173f7-1723693731681)]
对话框
modal modeless
对话框分为两种打开方式 ,modal 和 modeless
modal ShowDialog
modal对话框会中断程序的运行,暂停程序的主线程或事件循环,用户不能和其他窗口交互,直到用户关闭对话框。也就是说用户必须处理了对话框,主线程才能继续运行。比如手机用户输入,确认用户操作
实际上,打开对话框的代码会等待ShowDialog方法返回结果,才会接着运行modeless Show
modeless不会阻止用户激活其他窗口,也不会暂停程序,调用Show来显示非模式对话框,比如查找和替换对话框
MessageBox消息框
MessageBox表现得更像是(modal window),即在显示时会阻塞调用线程,直到用户与其交互完毕,也支持返回值,但是方法是Show,这更多是历史原因(继承自Winforms)
string messageBoxText = "Do you want to save changes?";
string caption = "Word Processor";
MessageBoxButton button = MessageBoxButton.YesNoCancel;
MessageBoxImage icon = MessageBoxImage.Warning;
MessageBoxResult result;
result = MessageBox.Show(messageBoxText, caption, button, icon, MessageBoxResult.Yes);
MessageBox.Show("Unable to save file, try again.");
MessageBox.Show("Unable to save file, try again.", "Save error", MessageBoxButton.OK, MessageBoxImage.Error);
result = MessageBox.Show(messageBoxText, caption, button, icon, MessageBoxResult.Yes);
switch (result)
{
case MessageBoxResult.Cancel:
// User pressed Cancel
break;
case MessageBoxResult.Yes:
// User pressed Yes
break;
case MessageBoxResult.No:
// User pressed No
break;
}
OpenFileDialog 打开文件对话框
// Configure open file dialog box
var dialog = new Microsoft.Win32.OpenFileDialog();
dialog.FileName = "Document"; // Default file name
dialog.DefaultExt = ".txt"; // Default file extension
dialog.Filter = "Text documents (.txt)|*.txt"; // Filter files by extension
// Show open file dialog box
bool? result = dialog.ShowDialog();
// Process open file dialog box results
if (result == true)
{
// Open document
string filename = dialog.FileName;
}
SaveFileDialog 保存文件对话框
// Configure save file dialog box
var dialog = new Microsoft.Win32.SaveFileDialog();
dialog.FileName = "Document"; // Default file name
dialog.DefaultExt = ".txt"; // Default file extension
dialog.Filter = "Text documents (.txt)|*.txt"; // Filter files by extension
// Show save file dialog box
bool? result = dialog.ShowDialog();
// Process save file dialog box results
if (result == true)
{
// Save document
string filename = dialog.FileName;
}
OpenFolderDialog 打开文件夹对话框
// Configure open folder dialog box
Microsoft.Win32.OpenFolderDialog dialog = new();
dialog.Multiselect = false;
dialog.Title = "Select a folder";
// Show open folder dialog box
bool? result = dialog.ShowDialog();
// Process open folder dialog box results
if (result == true)
{
// Get the selected folder
string fullPathToFolder = dialog.FolderName;
string folderNameOnly = dialog.SafeFolderName;
}
PrintDialog 打印对话框
// Configure printer dialog box
var dialog = new System.Windows.Controls.PrintDialog();
dialog.PageRangeSelection = System.Windows.Controls.PageRangeSelection.AllPages;
dialog.UserPageRangeEnabled = true;
// Show save file dialog box
bool? result = dialog.ShowDialog();
// Process save file dialog box results
if (result == true)
{
// Document was printed
}
自定义对话框
对话框本质是窗口,所以自己实现自定义对话框需要自己实现一个窗体
❌ 不要让对话框窗口变得杂乱无章。 对话框体验是让用户输入一些数据或做出选择。
✔️ 务必提供“确定”按钮来关闭窗口。
✔️ 务必将“确定”按钮的 IsDefault属性设置为 true
,以允许用户按ENTER键接受并关闭窗口。
✔️ 考虑添加“取消”按钮,以便用户可以关闭窗口并表明他们不想继续操作。
✔️ 务必将“取消”按钮的 IsCancel属性设置为 true
,以允许用户按 ESC 键关闭窗口。
✔️ 务必设置窗口标题,以准确描述对话框所代表的内容,或者用户应对对话框执行的操作。
✔️ 务必为窗口设置最小宽度和高度值,以防止用户将窗口调整得太小。
✔️ 如果 ShowInTaskbar设置为 false
,请考虑禁用调整窗口大小的功能。 可以通过将 ResizeMode设置为 NoResize 来禁用调整大小
✔️ 当按钮点击后会出现模式窗口交互,那么窗口的文本后面应该提供省略号,有助于用户确定,当他们选择这些菜单项时,系统会显示一个模式窗口
ShowDialog返回:
调用windows的ShowDialog时,代码会等待返回的结果,可以通过设置窗口上的DialogResult来提供返回值,并且设置了返回值以后,对话框会自动关闭
private void okButton_Click(object sender, RoutedEventArgs e) =>
DialogResult = true;
private void cancelButton_Click(object sender, RoutedEventArgs e) =>
DialogResult = false;
如果提供了IsCancel属性的按钮,并且使用了ShowDIalog打开窗口,那么按Escape会自动关闭窗口并将DialogResult设为False
对于show的情况,由于没有直接的返回值,所以要通过其他方式传递数据
- 公开一个属性
- 使用Closed事件或创建自定义事件
var marginsWindow = new Margins();
marginsWindow.Closed += (sender, eventArgs) =>
{
MessageBox.Show($"You closed the margins window! It had the title of {marginsWindow.Title}");
};
marginsWindow.Show();