WPF 控件测试器
WPF 控件测试器是一个小型应用程序,用于测试几个 WPF 控件和面板,以研究它们的行为。初学者 WPF 程序员可以通过研究此应用程序中使用的技术获益。

引言
本文将向您介绍我编写的一个名为“WPF 控件测试器”的示例应用程序。该应用程序的目的是研究和演示 WPF 自带的控件面板以及其他几个重要控件的行为。
背景
自几年前 WPF 技术推出以来,我一直断断续续地学习 WPF;不幸的是,我花费的时间更多的是“断”,而不是“续”。在长期使用 .NET Forms 控件以及之前的类似技术之后,我发现很难理解 XAML 的工作方式。那些熟悉的属性要么完全消失了,要么以全新的方式运行。
最近有一些空闲时间,我利用这个机会沉浸在 WPF 的学习中,我很庆幸现在我不仅开始掌握了 WPF,而且我还在享受 WPF,并且我可以看到它在许多方面都优于旧的方式。
作为我近期 WPF 研究的一部分,我编写了随本文提供的应用程序。该应用程序的大部分内容是特意用 XAML 编写的。除了少数为了方便而用 C# 编写的老式事件处理程序外,我想看看如何在不编写代码的情况下用 XAML 完成事情。一旦逻辑开始变得有意义,您就可以通过编写 XAML 完成很多事情。我确信我编写的一些代码可以以更好的方式完成,但有时我还是认为完成一个项目比把所有事情都做得尽善尽美更重要。
在接下来的文章中,我将简要介绍该应用程序,然后指出我在编程过程中发现的一些有趣的发现。
使用 WPF 控件测试器
您可以从此页面下载 WPF 控件测试器,有两个软件包可供选择。编译后的版本只需将其及其支持文件和文件夹解压缩到计算机上的任何文件夹即可“开箱即用”。否则,您可以下载源代码,以便审阅和进行自己的修改,然后从源代码编译并运行应用程序。
该应用程序创建了六个测试窗口来演示几个 WPF 控件的各种功能。所有这些窗口都可以在主启动窗口中访问。这里提供了每个窗口的缩略图(加上另外两个),并附有详细说明。
![]() |
![]() |
![]() |
![]() |
边距和内边距 | StackPanels | WrapPanels | DockPanels |
![]() |
![]() |
![]() |
![]() |
Grids | Canvas Panels | 帮助窗口 | 上下文菜单 |
边距和内边距
边距和内边距窗口演示了所有 WPF 控件上 Margin
和 Padding
属性的使用。它演示了当使用一个数字、两个数字和四个数字来设置属性时,这些属性的行为方式。通过比较顶部、中部和底部行中显示的输出,可以轻松看出 Margin
设置和 Padding
设置之间的区别。
为了进行演示,我使用了 Label
包裹在 Border
中,以便于区分 Margin
定义的区域(红色 Border
外面的绿色区域)和 Padding
定义的区域(红色 Border
内部包围 Label
文本的区域)。
StackPanels
下一个窗口是StackPanels。在此窗口中,展示了两个 StackPanel 对象,以演示 Orientation="Vertical"
和 Orientation="Horizontal"
之间的区别。这可能是六个测试窗口中最简单的。作为一点有趣的说明,我决定在此窗口中使用 Grid
来组织和分隔两个 StackPanel
。这也可以通过其他面板完成,包括 StackPanel
,所以有时在一种面板和另一种面板之间进行选择仅仅是偏好的问题。
WrapPanels
WrapPanels 窗口与StackPanels 窗口非常相似。比较两个窗口的 XAML 会发现,除了 WrapPanel
和 StackPanel
标签之外,视觉元素几乎没有区别。在 Resources
部分创建的 Style
中,我为 WrapPanel
添加了两个 Setter
标签,它们不属于 StackPanel
Style
,一个是 ItemWidth
,另一个是 ItemHeight
。
与StackPanels 窗口一样,WrapPanels 也有两个 WrapPanel
对象,演示了 Orientation
的水平和垂直设置。
DockPanels
DockPanels 窗口演示了 WPF 中可能最有用的面板。将控件添加到 DockPanel
时,您可以通过附加属性 DockPanel.Dock
指定控件应停靠在哪一侧。此窗口显示了控件添加的顺序如何影响其可用的空间。该窗口还演示了将 LastChildFill
设置为 True
或 False
的效果。
Grids
最后两个窗口是最有趣的。Grids 窗口说明了 Grid
中的行和列是如何设置的,以及设置 RowDefinition
的 Height
或 ColumnDefinition
的 Width
为 "Auto"
或 "*"
的大小调整效果。
Canvas Panels
最后一个测试窗口称为Canvas Panels,它演示了附加属性 Canvas.Left
和 Canvas.Top
以及常规 Margin
属性如何组合以影响控件在 Canvas
上的放置。
我需要帮助!没问题。
通过右键单击这些窗口,可以在帮助窗口中找到有关所演示控件的额外信息。这将打开一个上下文菜单。单击顶部的菜单选项将打开一个新窗口,其中包含有关该窗口和那里演示的控件的信息。
关注点
除了测试窗口中提供的演示之外,应用程序的代码还有其他有趣之处。为了方便打开测试窗口,我在启动窗口的 Window.Resources
中添加了每个窗口的一个实例,然后使用 Binding
将每个窗口绑定到其 Button
,并使用 Button Style
将每个 Button
的 Content
属性设置为其窗口的 Title
属性,并将窗口本身设置为 Button
的 Tag
属性。(请参阅 LaunchWindow.xaml
获取相关标记。)
然后,启动窗口就变得很简单,只需将 Sender
转换为 Window
并使用其方法使其出现。为了防止窗口在程序运行时被处理掉,LaunchWindow
的 button_Click
事件处理程序向其启动的任何窗口添加了一个事件处理程序。然后,当 LaunchWindow
检测到窗口试图关闭时,它会拦截并简单地使窗口不可见。后续打开相同窗口的请求会通过使窗口可见然后使其成为活动窗口来得到满足。
我在调试时发现,当我退出程序(通过关闭所有窗口)时,程序实际上并不会停止运行。起初这让我很困惑,因为在我的测试过程中,我总是先关闭测试窗口,然后再关闭启动窗口。我曾假设关闭该窗口会使其资源被处理掉,从而自动关闭所有测试窗口。我的想法错了。
也许将 LaunchWindow
设置为每个测试窗口的 Owner
会使程序按我预期的方式工作,但我没有对此进行测试。相反,我重写了 OnClosing
来在 LaunchWindow
关闭时关闭每个测试窗口。然而,另一种技术可能在不采取措施移除用于防止测试窗口关闭的事件处理程序的情况下不起作用,并且当测试窗口调用已被处理掉的对象的事件处理程序时,可能会导致其他问题。(请参阅 LaunchWindow.xaml.cs
获取讨论的代码。)
还有其他几项可能对程序员有益。一个是在 HelpWindow
中使用 Frame
元素来显示为项目创建的 html
帮助文件。在 HelpWindow.xaml 和 HelpWindow.xaml.cs 中查找用于实现此功能的标记和代码隐藏。
另一个是添加启动屏幕在应用程序打开时显示的简单性。(只需向项目中添加一个图像,并将其 Build Action
属性设置为 SplashScreen
。)起初,这个应用程序启动得很快,以至于没有足够的时间显示启动屏幕,所以我会在 App()
构造函数中添加一个短暂的延迟,然后再在 App.xaml.cs
中显示第一个窗口。
最后,您可能想看看也位于 App.xaml.cs
中的上下文菜单的事件处理程序。因为同一个 ContextMenu
用于所有可用的窗口,所以我必须找到一种方法来确定哪个窗口参与了请求。我知道 WPF 中有更好的方法来处理这个问题,但对于这个快速应用程序,我编写了代码来从生成事件的 MenuItem
中查找 ContextMenu
对象,然后从 ContextMenu
中,PlacementTarget
属性给了我一个事件调用的窗口中的控件。一旦我有了那个,我只需要沿着 Parent
项目的路径找到合适的 Window
,然后我就可以确定在帮助窗口中加载哪个帮助文件了。
我很高兴能一起完成这个应用程序,并在这里写下它。我的目的主要是自私的,希望通过这条道路,我能更好地理解这项技术。然而,我也希望这能帮助其他人比没有它的时候更快地理解 WPF。
尽情享用!
历史
2012 年 1 月 29 日 - 原始提交。