Windows

Windows(窗体)是一个容器,所有需要显示的内容都需要在window里面,用户的交互也是全部基于windows,WPF就是Windows Presentation Foundation的简写,这里面的windows可以理解为操作系统,但是未尝不可以理解成窗体(windows系统的命名可能就是基于这个考量)

基类是window,提供了以下功能

  1. 窗体相关功能,如标题栏、最小化、最大化、关闭按钮,以及可拖动和调整大小的边框。
  2. 提供一个容器来容纳指定内容,content属性来指定窗口的内容
  3. 控制窗体的生命周期和其他属性
<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属性

  1. Content 属性

    • WindowContent 属性用于指定窗口的主要内容,可以是一个控件或一个控件的集合(例如,布局控件 Grid, StackPanel 等)。
  2. Title 属性

    • Title 属性用于设置窗口的标题栏文本。它显示在窗口的顶部,并通常用于描述应用程序的名称或窗口的目的。
  3. Width 和 Height

    • 这些属性用于设置窗口的宽度和高度。它们可以在 XAML 或代码中定义。
      MinWidth和 MaxWidth用于管理窗口在其生存期内可以具有的宽度范围,同样的还有Height
      也可以根据内容自适应
    • SizeToContent.Manual不起作用(默认值)。
    • SizeToContent.Width 适应内容宽度(固定宽度,相当于将最小宽度和最大宽度都设成固定的)
    • SizeToContent.Height 适应内容高度(固定)
    • SizeToContent.WidthAndHeight 适应宽高(固定)
<Window 
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
    SizeToContent="WidthAndHeight">
</Window>
  1. WindowStartupLocation
    • WindowStartupLocation 属性指定窗口首次显示时的位置。常见的值包括 CenterScreen(屏幕中央)和 Manual(使用 LeftTop 手动设置)。
      同时,除了有x,y值表示位置外,窗口还有z值,表示窗口的前后
      只有两种,一种是正常的,一种是最顶层(TopMost)
  • 正常 Z 顺序(Normal Z-order):
    默认情况下,所有窗口都位于正常 Z 顺序中。在这个顺序中,窗口的显示顺序取决于窗口是否处于活动状态。活动窗口通常显示在其他非活动窗口的前面。
    当一个窗口被用户点击或通过代码激活时,它会在 Z 顺序中提升,并显示在其他非活动窗口的前面。
  • 最顶层 Z 顺序(Topmost Z-order):
    最顶层 Z 顺序中的窗口始终显示在正常 Z 顺序中的所有窗口之上,无论它们是否处于活动状态。
    窗口可以通过将其 Topmost 属性设置为 true 来进入最顶层 Z 顺序。当 Topmost 属性为 true 时,该窗口始终保持在所有其他非最顶层窗口的前面,即使这些窗口被激活也是如此。
  1. WindowState

    • WindowState 属性表示窗口的状态,如 NormalMinimizedMaximized
    // 最大化窗口
    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.ActivatedApplication.Deactivated用于应用程序的激活通知

Preventing Window Activation(防止窗口激活)

有时需要防止窗口被激活,比如显示一个仅用于信息显示的窗口。
可以在Show方法前将ShowActivated属性设成False

Closing a Window(关闭窗口)

关闭窗口可以通过调用 Window.Close() 方法。关闭窗口会触发 ClosingClosed 事件。Closing 事件在窗口关闭之前触发,可以用于检查是否允许关闭窗口。Closed 事件在窗口关闭后触发。
窗口关闭后,就不能重新打开了

// 关闭窗口
myWindow.Close();
Cancel Window Closure(取消窗口关闭)

Closing 事件的事件处理程序中,可以通过设置 CancelEventArgs.Canceltrue 来取消窗口的关闭操作。例如,当有未保存的更改时,弹出确认对话框让用户决定是否取消关闭操作。一旦调用了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(窗口生命周期事件)
  1. SourceInitiated:窗口初始化时触发(调用Show时)。
  2. Activated:窗口激活时触发(Show时不一定会激活)。
  3. Loaded:窗口加载完成时触发。
  4. ContentRendered窗口有Content时触发
  5. Deactivated:窗口失活时触发。(可能不会失活)
  6. Closing:窗口开始关闭时触发。只有用户关闭窗口时会触发
  7. Deactivated:窗口关闭前一定会失活。
  8. 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的情况,由于没有直接的返回值,所以要通过其他方式传递数据

  1. 公开一个属性
  2. 使用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();
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 213,752评论 6 493
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,100评论 3 387
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 159,244评论 0 349
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,099评论 1 286
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,210评论 6 385
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,307评论 1 292
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,346评论 3 412
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,133评论 0 269
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,546评论 1 306
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,849评论 2 328
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,019评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,702评论 4 337
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,331评论 3 319
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,030评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,260评论 1 267
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,871评论 2 365
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,898评论 2 351

推荐阅读更多精彩内容