当前位置: 移动技术网 > IT编程>开发语言>.net > [WPF自定义控件]Window(窗体)的UI元素及行为

[WPF自定义控件]Window(窗体)的UI元素及行为

2019年06月11日  | 移动技术网IT编程  | 我要评论

一起看电影,连江在线,鞭炮的图片

1. 前言

本来打算写一篇《自定义window》的文章,但写着写着发觉内容太多,所以还是把使用windowchrome自定义window需要用到的部分基础知识独立出来,于是就形成了这篇文章。

无论是桌面编程还是日常使用,window(窗体)都是最常接触的ui元素之一,既然window这么重要那么多了解一些也没有坏处。

2.标准window

这篇文章主要讨论标准的window,不包括奇形怪状的无边框、非矩形window,即只讨论windowstyle="singleborderwindow"(默认值)的window。

一个标准的window的基本构成如上图所示,它主要由非工作区(non-client area)和工作区(client area)组成。上图中中间白色的部分即client area,在wpf对应下面代码中注释的部分:

<window 
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    x:class="sdksample.markupandcodebehindwindow">
  
  <!-- client area (for content) -->
  
</window>

标准window中除client之外的部分称为non-client area,通常称之为chrome,它提供了提供了标准的窗口功能和行为,具体包含以下部分:

  • 边框
  • 阴影
  • 标题栏
  • icon
  • 标题
  • systemmenu
  • 最小化最大化还原按钮
  • 关闭按钮
  • 大小调整手柄

边框

标准window肯定会有边框的,在windows 7上因为有aero效果所以看上去很棒,现在偶尔用用windows 7还是觉得很漂亮。但就如上图所示圆角不够平滑,如果电脑不是高分屏的话应该会更明显,例如这样:

因为圆角总是很难处理所以我不是很喜欢圆角的设计。

windows 10的边框就时髦很多,如果在“个性化>颜色”设置页面取消标题栏和窗口边框,看上去就像是无边框(其实是把边框做成白色的了):

阴影

阴影用于体现ui的深度,属于装饰元素,windows 的窗体通常都带有阴影,除非在“系统属性->高级->性能选项->视觉效果”里关闭“在窗口下显示阴影”选项。

标题栏

只要是标准的window就应该有标题栏。一些浏览器看上去没有标题栏;当fluent design system出来后流行将内容扩展到标题栏,越来越多的应用看上去没有了标题栏。其实标题栏总是存在,能拖动,点击右键会弹出systemmenu,并且最右边有关闭按钮的部分就是标题栏了。

双击标题栏还可以执行最大化还原操作。

有一点细节可能不太容易注意到,当window处于最大化状态时标题栏比较矮。在100% dpi时标题栏的高度为30像素,最大化时变为22像素,这时候右上角的几个按钮缩小了,其它元素的margin也减少了一些。

icon

icon是指标题栏左边的窗体图标,这倒真的很常消失。在100% dpi的情况下它是个16 * 16 像素的图片。

顺便一提双击icon会关闭window,但我想一般都会用右边的关闭按钮的吧。

标题

标准window的标题位于icon右边。如果window边框是深色,标题文字颜色为白色;反之则为黑色。

systemmenu

在标题栏上点击鼠标右键出现的contextmenu即是systemmenu,它包括调整大小、移动和关闭操作。在icon上点击鼠标左键,或者按alt+空格都会在标题栏左下方弹出systemmenu

不过很少见到有人用systemmenu,我也只是用它来确定标题栏的范围而已。

最小化、最大化和还原按钮

当window的resizemode设置为noresize以外的值时(即canminimizecanresizecanresizewithgrip)这三个按钮才会出现,如果resizemode设置为canminimize最大化还原都会被禁用。

关闭按钮

因为关闭按钮基本上一定会存在所以把它独立出来,只是resizemode设置为noresize关闭按钮会比较小。在windows 10中最大化时关闭按钮贴着右上角,这样比较方便鼠标操作。

调整大小

当window的resizemode设置为canresizecanresizewithgrip时window可以使用最大化还原按钮或systemmenu调整大小,也可以通过拖动边框调整大小。

大小调整手柄

当window的resizemode设置为canresizewithgrip并且windowstate = normal时右下角会出现大小调整手柄,外观为组成三角形的一些点。除了让可以操作的区域变大一些,还可以用来提示window是可以调整大小的。

拖动

有些window会做成整个window都可以通过拖动来改变位置,标准window则只有标题栏可以拖动。

激活

激活或非激活的window之间的区别主要体现在标题栏、边框及标题文字的颜色。在标题栏使用了acrylicbrush的uwp应用还体现在非激活时acrylicbrush变成纯色不透明的brush。

焦点

一个window中只有client area中的内容可以获得键盘焦点,而且tab键只会让键盘焦点在window的内容中循环。当一个window从非激活状态会到激活状态,之前获得键盘焦点的元素将重新获得键盘焦点。

动画

window在最大化、最小化、还原有缩放的动画,这个动画可以清晰地指示window的最终位置。当任务栏内容很多的时候,向下缩放到任务栏对应位置的动画尤其重要。

flashwindow

如果一个window设置了owner并且以showdialog的方式打开,点击它的owner将对这个window调用flashwindowex功能,即闪烁几下,并且还有提示音。除了这种方式还可以用编程的方式调用flashwindow功能。

window的大小

最后要说的是window的大小。window的实际大小并不是表面上看到的大小。在windows 10,以1920 * 1080 分辨率,100% dpi为例,打开以下xaml定义的一个window:

<window x:class="wpfapp1.mainwindow"
        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"
        mc:ignorable="d"
        title="mainwindow"
        height="600"
        width="800">
    <grid x:name="layoutroot">
    </grid>
</window>

通过实时可视化树可以看到,window本身的小时确实是800 * 600,但layoutroot的大小只有784 * 561。将window最大化后window的大小变为1936 * 1066,而layoutroot的大小变为1920 * 1027。

如果将window设置为启动位置在左上角:

windowstartuplocation="manual"
top="0"
left="0"

结果它并不会完全贴着左上角,而是左边有一点空间,上面没有。

通过inspect看到的window如下,黄色边框为它的实际范围:

可以看到系统理解的window范围和我们看到的不同,这是window设计的问题,有几个值用于计算chrome的尺寸:

属性 值(像素) 描述
sm_cxframe/sm_cyframe 4 the thickness of the sizing border around the perimeter of a window that can be resized, in pixels. sm_cxsizeframe is the width of the horizontal border, and sm_cysizeframe is the height of the vertical border.this value is the same as sm_cxframe.
sm_cxpaddedborder 4 the amount of border padding for captioned windows, in pixels.windows xp/2000: this value is not supported.
sm_cycaption 23 the height of a caption area, in pixels.

在有标题的标准window,chrome的顶部尺寸为sm_cyframe + sm_cxpaddedborder + sm_cycaption = 31,左右两边尺寸为sm_cxframe + sm_cxpaddedborder = 8,底部尺寸为sm_cyframe + sm_cxpaddedborder = 8。

最大化情况下border和resizeborder都超出屏幕范围而且被隐藏了,所以window的尺寸会超过显示器工作区的尺寸,这时候标题栏也会相应地变矮。在windows 10,系统认为window有4像素的resizeborder,但因为windows 10是窄边框设计,而且在普通状态下和最大化状态下的标题栏高度还不一样,导致用uispy观察window和我们看到的window不一致,也常常导致位置计算上的问题。

注意,上面的尺寸计算都是基于100 % dpi,在不同dpi的情况下还需要将dpi的值纳入计算。

3. 结语

标准window的外观和行为基本上已经列出来了(其实还有很多,例如按住标题栏抖一抖可以缩小其它所有窗口这种功能,但这些不影响自定义window的行为就不一一列出了),更多的内容请见下面给出的参考链接。

顺便一提设置sizetocontent="widthandheight"并且 windowstate="maximized"的window行为很怪异,最好不要这样设置。

4. 参考

wpf windows 概述 _ microsoft docs

对话框概述 _ microsoft docs

systemparameters class (system.windows) microsoft docs

如对本文有疑问,请在下面进行留言讨论,广大热心网友会与你互动!! 点击进行留言回复

相关文章:

验证码:
移动技术网