通过增强的 Windows Forms 支持为 .NET 应用程序精心制作华丽的 UI
本文将介绍以下内容:
• |
Windows Forms 控件的新增功能 |
• |
设置和资源管理 |
• |
布局、调整大小和缩放 |
• |
数据绑定 |
• |
ClickOnce 部署 |
本文涉及以下技术:
Windows Forms、Visual Studio、.NET Framework 2.0
![*](http://img.microsoft.com/library/gallery/templates/MNP2.Common/images/3squares.gif)
本页内容
Windows Forms 2.0 比它之前的任何 Windows 应用程序开发平台的功能都要丰富得多。您将会发现全方位的改进:采用更为紧凑的全功能 Microsoft® .NET Framework、Visual Studio® 与许多新的附加设计器的集成更为紧密、采用统一的数据绑定模型以及锦上添花的 ClickOnce Web 样式部署。
System.Windows.Forms 命名空间(构成 Windows® Forms 之技术的核心)得到了显著改进。命名空间(由公共类型(类和枚举)组成)的可使用表面区域比 .NET Framework 1.1 增加了约 134%。新增了 446 种公共类型;113 个现有类型使用新成员和新值进行了更新;原有命名空间中的 218 种类型得到了保留;而且没有删除任何类型。这是一次覆盖范围很广的发布。事实上,其覆盖范围广到我们没有足够的篇幅来做全面介绍。不过,图 1 可以让您有一个大致的了解。功能可真是不少!它们都等着您在创建新的 Windows Forms 项目时将它们派上用场。
Windows Forms 项目
![](http://www.microsoft.com/china/msdn/library/langtool/vs2005/art/SmartClients_fig02.gif)
图 2 Windows Forms 项目结构
无论您偏好使用 C# 还是 Visual Basic®,创建新 Windows Forms 项目时首先引起您注意的都将是 Visual Studio Windows 应用程序项目向导生成的新默认项目结构,如图 2 所示。更新的结构具有若干个项目增强功能,我们将对这些功能进行介绍。
代码分离
新默认项目结构的一个目标是从默认 Form1 中删除代码。如果使用的是 C#,裁减后所得到的实施代码与以下内容类似:
// Form1.cs partial class Form1 :Form { public Form1() { InitializeComponent(); } }
Visual Basic 在代码裁减操作上花费的时间会略长:
' Form1.vb Public Class Form1 End Class
您可能想知道 InitializeComponent 到哪里去了。在 Windows Forms 2.0 中,设计人员管理的窗体代码(如 InitializeComponent 方法)保留在新文件 FormName.Designer.cs 或 FormName.Designer.vb 中。这种分离旨在避免开发人员与 Windows Forms 设计人员之间发生争执,在 C# 和 Visual Basic 中可以通过为 partial class 提供新语言支持来启用该功能,如下面的示例代码所示:
// Form1.cs(开发人员管理的) public partial class Form1 :Form { ... } // Form1.Designer.cs(设计人员管理的) partial class Form1 { ... void InitializeComponent() { ... } ... }
下面是起同样作用的 Visual Basic 代码:
' Form1.vb(开发人员管理的) Public Class Form1 End Class ' Form1.Designer.vb(设计人员管理的) Partial Class Form1 Inherits System.Windows.Forms.Form ... Private Sub InitializeComponent() ... End Sub ... End Class
如果您是 C# 开发人员,可能也想知道向导生成的静态 Main 方法到哪里去了。因为 Main 的作用域是应用程序而不是窗体,所以它已经被移动到其自己的文件 Program.cs 中:
// Program.cs static class Program { /// <summary> /// 应用程序的主要入口点。 /// </summary> [STAThread] static void Main() { ... } }
默认情况下 Visual Basic 项目配置为在应用程序启动时即启动 Form1。必要时可以使用自定义 Shared Sub Main 入口点。代码分离的结果是,开发人员可以集中精力只编写解决其特定问题所需的代码。
改进的资源管理
IDE 本身进行了更新,以简化 Windows Forms 2.0 编程。Visual Studio 资源编辑器得到了急需的改进,所带来的主要益处是提高了管理和查看资源实际外观的能力,如图 3 所示。
![](http://www.microsoft.com/china/msdn/library/langtool/vs2005/art/SmartClients_fig03.gif)
图 3 Visual Studio 资源编辑器
现在,在资源编辑器中可以通过多种机制添加新文件和现有文件,其中包括图 3 所示的下拉列表、从“剪贴板”粘贴和拖放操作。无论采用何种机制,资源都会自动归入下列类别之一:Strings(字符串)、Images(图像)、Icons(图标)、Text Files(文本文件)和 Sound Files(声音文件)。还有一个类别 Other(其他),用于像组件定义的设计时数据序列化这样的资源数据。要查看每个类别,请选择资源编辑器左上方的下拉列表。每个类别都会根据它所包含的资源类型进行调整来提供专门的视图。例如,您可以通过 Details(详细资料)、List(列表)或 Thumbnail(缩略图)视图来查看字符串以外的所有资源类型,就像在 Windows 资源管理器中那样。
另一项重要改进就是提供了指定资源是嵌入资源还是链接资源的功能。通过属性编辑器添加到项目中的嵌入资源存储在项目范围资源 (.resx) 文件中。链接资源(字符串以外资源的默认设置)表示 Visual Studio 引用项目系统外部的文件,这使不同的人可以更方便地管理资源数据(所需的图形和声音数据),同时开发人员又可以从事他们最擅长的工作:创建应用程序。Visual Studio 在这一方面也为开发人员提供了便利。
设想一下以前在使用 Windows Forms 1.x 时从代码中检索字符串资源所需执行的步骤:
// 加载项目资源文件中的字符串资源 Assembly assem = Assembly.GetExecutingAssembly(); ResourceManager resman = new ResourceManager("MyApp.Resource1", assem); string myStringResource = resman.GetString("MyString");
再设想一下采用 Windows Forms 2.0 所支持的简化强类型化方法时所需执行的步骤:
// 加载强类型化字符串资源 string myString = Properties.Resources.MyString;
Windows Forms 此时生成了类 Resources(位于 ProjectName.Properties 命名空间内),它通过强类型化静态(共享)属性来提供每个资源。现在,对于代码中包括图标、图像和声音在内的任何资源类型,都可以轻松地将它们作为字符串进行检索:
// 所有类型的强类型化资源 string myString = Properties.Resources.MyString; Icon myIcon = Properties.Resources.MyIcon; Image myImage = Properties.Resources.MyImage; UnmanagedMemoryStream mySound = Properties.Resources.MySound;
再向项目中添加其他 .resx 文件时,也会导致生成强类型化包装类。
改进的设置管理
项目属性页上提供了一个新的 Settings Editor(设置编辑器),可以通过它向下列两个作用域之一添加设置:应用程序和用户。应用程序设置(如数据库连接字符串和 URL)是永久性设置,应用程序安装后便不会更改。用户设置(如 Tools(工具)| Options(选项)菜单中的设置)是一些默认设置,用户可以在安装后进行更改。图 4 显示了运行中的 Settings Editor(设置编辑器)。
![](http://www.microsoft.com/china/msdn/library/langtool/vs2005/art/SmartClients_fig04.gif)
图 4 Visual Studio Settings Editor(设置编辑器)
Settings Editor(设置编辑器)通过应用程序的配置文件 (ApplicationName.exe.config) 来部署应用程序设置和用户设置。与资源类似,Windows Forms 也会生成强类型化包装类(位于 ProjectName.Properties 命名空间内)。应用程序设置作为只读属性来实现,而用户设置则作为读/写属性来实现。二者都可以通过生成的静态(共享)Default 属性以编程方式进行检查或更新:
// 检查以应用程序为作用域的设置 string myAppSetting = Properties.Settings.Default.MyApplicationSetting; // 更新以用户为作用域的设置 Properties.Settings.Default.MyUserSetting = "myNewUserSettingValue";
由于用户希望他们对设置进行的更改能够从一个应用程序会话延续到下一个会话,因此需要在一个会话结束时保存更改后的用户设置,并在另一个会话开始时重新加载该设置。尽管在每个会话开始时用户设置和应用程序设置会自动加载,但必须在会话结束时通过调用 Save 方法来手动保存用户设置,该方法由生成的 Settings 类提供,如下所示:
void OptionsForm_FormClosing(object sender, FormClosingEventArgs e) { // 保存用户设置以供下一次使用 Properties.Settings.Default.Save(); }
应用程序设置是只读的,用户设置则不是,而且将其保存到的文件不能是应用程序配置文件。因此,Windows Forms 会将用户设置保存到 user.config,它位于与用户绑定的 Windows 兼容文件系统位置。该文件的路径会视某些条件(如是否启动了漫游)而异。下面的位置由独立应用程序使用:
%InstallRoot%\Documents and Settings\UserName\ Local Settings\Application Data\ProductName\ ApplicationName.exe_Url_UrlHash\AssemblyVersionNumber
有时用户将设置更改为他们并不想要的值,但已经记不清先前的设置了。在这种情况下,可以通过调用 Settings 对象的 Reload 方法来提供恢复为最后保存设置的机制:
void reloadSettingsButton_Click(object sender, EventArgs e) { // 恢复为最后保存的用户设置 Properties.Settings.Default.Reload(); }
其次,如果用户设置被完全覆盖,可以恢复到应用程序最初部署的设置:即在 Settings Editor(设置编辑器)中输入的值。恢复这些值需要调用 Settings 对象的 Reset 方法:
void resetButton_Click(object sender, EventArgs e) { // 恢复为安装时的默认用户设置 Properties.Settings.Default.Reset(); }
用户设置采用下面这种方式来管理:如果删除 user.config 文件,这些设置的默认值将加载到下一个应用程序会话中。
System.Windows.Forms.Form
Visual Studio 是用来构建 Windows Forms 应用程序的最重要工具,System.Windows.Forms.Form 则是最重要的类。正如您所期待的那样,此类进行了更新,现在添加了一些重要的新成员,图 5 中列出了这些新成员。到目前为止,新成员中最值得关注是那些与布局有关的部分。
捕捉线、边距和填充
将控件拖动到窗体上并将它们四处拖动时,可以使用捕捉线来对齐控件。将控件拖动到窗体上时,捕捉线显示为一条或多条粘性线,它们会引导控件与其他控件在水平和垂直两个方向上都紧邻共用文本基线和文本边距的地方对齐(请参阅图 6)。
![](http://www.microsoft.com/china/msdn/library/langtool/vs2005/art/SmartClients_fig06.gif)
图 6 捕捉线
除相互对齐外,控件彼此间还需保持合理的间距。尽管捕捉线不能满足调整间距的需要,但控件上提供的两个新属性却可以做到:填充和边距。填充是指从窗体或控件工作区边缘算起、子控件(以及文本和图像等)不能强行进入的内部距离(像素)。边距是指从控件边缘算起、其他控件不能强行进入的外部距离。拖动控件时,如果控件与窗体间的距离是其边距与填充之和,则会在控件和窗体之间显示一条蓝线。图 7 显示了用来确定何时控件具有正确间距的边距和填充。可以一次指定所有边缘的填充和边距属性,也可以分别指定各边缘的填充和边距属性。
![](http://www.microsoft.com/china/msdn/library/langtool/vs2005/art/SmartClients_fig07.gif)
图 7 边距和填充的使用
自动调整大小和缩放
由于捕捉线、边距和填充只是一些辅助线,因此可能会被忽略,这就可能导致在移动控件或调整控件大小时,控件会被部分或完全隐藏。您将需要调整容器控件大小来显示调整了大小或进行了移动的控件的隐藏部分,如果涉及许多控件,就会成为一项枯燥乏味的工作。实际上可以使用 AutoSize 和 AutoSizeMode 属性来完成这项工作。AutoSize 是一种布尔属性,设置为 true 时,将会指示控件自动调整大小来适应其内容。AutoSizeMode 属性会指示控件如何调整大小,即按照 AutoSizeMode (System.Windows.Forms) 枚举的 GrowOnly 和 GrowAndShrink 值的指定调整大小。
GrowOnly 指定如果容器所包含控件的新尺寸等于或大于原尺寸,容器应自动调整大小。GrowAndShrink 指定容器应增大或减小尺寸来响应所包含控件的大小调整和移动,如图 8 所示。
![](http://www.microsoft.com/china/msdn/library/langtool/vs2005/art/SmartClients_fig08.gif)
图 8 使用 GrowAndShrink 自动调整大小
当控件边缘与宿主容器右边缘和底边缘(它们的边距重叠区)靠得足够近时,将会触发自动大小调整。有多种控件都支持仅使用 AutoSize,或同时使用 AutoSize 和 AutoSizeMode。有一些控件(如窗体)确实实现了这两个属性,但只会在运行时使用它们。您将需要试着使用每一个控件,才能确定其自动调整大小支持的程度。
除了可以自动调整大小来适应内容外,窗体和控件还可以在所有 DPI 设置中自动调整大小,同时保持尺寸和位置比例不变。要在多个 DPI 设置中保持相同的比例(或称缩放),需要两个重要元素。第一个元素指示窗体进行自动缩放。第二个元素指示窗体对窗体及其控件的尺寸和位置应用什么缩放系数。默认情况下,窗体通过其 AutoScale 属性(设置为 true)进行自动缩放。缩放系数由 AutoScaleMode 属性指定,其值可以是下列值之一:
enum AutoScaleMode { None = 0, // 不缩放 Font = 1, // 根据字体大小缩放(默认值) Dpi = 2, // 根据 dpi 缩放 Inherit = 3 // 继承容器的 AutoScaleMode }
默认值为 Font,表示缩放系数是以窗体创建和执行窗体时默认系统字体平均宽度和高度的比率为基础的。例如,如果在 Windows XP 常规字体 (96 DPI) 下创建窗体,默认字体将为 8.25pt MS Sans Serif,平均宽度和高度为 6x13。此信息由 Windows 窗体设计器自动存储在窗体的 AutoScaleDimensions 属性中:
// AutoScalingForm.designer.cs partial class AutoScalingForm { ... void InitializeComponent() { ... this.AutoScaleDimensions = new SizeF(6F, 13F); ... } }
如果后来在默认字体为 7.8pt MS Sans Serif 的大字体 (120 DPI) 下重新打开窗体或执行窗体,字体的平均宽度和高度将增加到 8x16。窗体会注意到 AutoScaleDimensions 与当前缩放尺寸之间的差异,然后根据计算的差异来调整其控件的宽度、高度和位置。这样一来,无论系统字体怎样设置,都可使窗体的总体外观保持大致相同。在 Visual Studio 内部同一行为也将保持一致。
AutoSizeMode.Font 使缩放以各 DPI 之间的字体差异为基础,AutoSizeMode.Dpi 则使缩放完全以各 DPI 之间的差异为基础。图 9 对这两种模式做了比较。
![](http://www.microsoft.com/china/msdn/library/langtool/vs2005/art/SmartClients_fig09.gif)
图 9 从 96 DPI 自动缩放到 120 DPI
AutoScaleMode.Font 和 AutoScaleMode.Dpi 之间在实际使用时的区别是,前后两者的缩放率不同,因为成比例字体的缩放方式不同于纯线性的 DPI 缩放,这一点在不同语言的缩放上体现的尤为明显。AutoScaleMode.Font 是默认选项,因为它是最可靠的选项。
TableLayoutPanel 和 FlowLayoutPanel
尽管捕捉线、边距、填充、自动调整大小和自动缩放组成了一个有用的布局工具箱,但它们无法方便地支持可调整大小对话框中包含相当多控件的更复杂情况。由于对此类情况有所预见,Windows Forms 加入了两个新的布局控件:TableLayoutPanel 和 FlowLayoutPanel。
TableLayoutPanel 支持 HTML 样式表布局。可以通过下列三种方法之一来定义可配置为自动调整大小的行和列:
• |
自动调整大小:自动调整大小来适应其内容 |
• |
百分比:大小是 TableLayoutControl 总高度或宽度的百分比 |
• |
绝对大小:固定大小(像素) |
通过 Windows 窗体设计器可以合并行和列及调整它们的大小。每个单元格可以只包含一个控件,其在单元格内的位置随停靠和定位而变。图 10 显示了作用中的 TableLayoutPanel 示例。它还显示了驻留在嵌套 TableLayoutPanel 内的“确定”和“取消”按钮;需要在每个单元格中放置多个控件时,嵌套 TableLayoutPanel 是一种很有用的方法。
![](http://www.microsoft.com/china/msdn/library/langtool/vs2005/art/SmartClients_fig10.gif)
图 10 TableLayoutPanel 控件
FlowLayoutPanel 支持 HTML 样式流布局。通过将其 FlowDirection 属性设置为以下四个值之一,可以指示 FlowLayoutPanel 在调整大小过程中应将包含的控件推向哪个方向:LeftToRight、TopDown、RightToLeft 和 BottomUp。
与处理 Web 页时相同,调整 FlowLayoutPanel 大小时也可以使其包含的控件完全无法再进行移动,从而使这些控件部分或全部为 FlowLayoutPanel 的垂直和/或水平边缘覆盖。在这些情况下,可以根据需要将 AutoScroll 属性设置为 true,以提供垂直和水平滚动条。
控件和组件
Windows Forms 2.0 提供了一整套以填补先前工具箱漏洞为主要目标的新控件和组件,其中包括 MaskedTextBox、WebBrowser 和 BackgroundWorker。此外,控件和组件库也进行了各种全方位的改进,其中包括使常用控件以实时方式在外观上适应当前 Windows 主题的功能,以及支持在设计器中使用智能标记来使开发者能够更快速、更集中精力地完成配置。
MaskedTextBox 控件
MaskedTextBox 控件是为了使数据输入更有依据、更为准确而设计的,它会就需要使用掩码输入的数据类型和形式给出提示,引导用户完成输入(请参阅图 11)。有许多掩码字符;如果在构建和测试掩码时需要帮助,请从 Properties(属性)窗口打开 MaskedTextBox 控件的 Input Mask Editor(输入掩码编辑器)。
![](http://www.microsoft.com/china/msdn/library/langtool/vs2005/art/SmartClients_fig12.gif)
图 12 MaskedTextBox
默认情况下,非掩码字符(如括号、连字符和空格)均视为文字,将在运行时显示以描述所需数据的形式,而所有掩码字符在运行时将由提示字符替换(默认情况下为下划线,仅当焦点位于 MaskedTextBox 上时才会显示,如图 12 所示)。MaskedTextBox 实现了多种属性,图 13 中列出了其中最值得注意的一些属性。MaskedTextBox 是一个可配置性很强的控件,如果想为用户提供更有依据的数据输入体验,应该考虑使用该控件。
Web 浏览器
尽管 Windows Forms 应用程序在任何情况下都可以通过互操作功能使用 COM 控件来支持 Web 浏览,但编程体验略为凌乱。不过,新的 Web 浏览器控件提供了一种有条理的方式来轻松地为 Windows Forms 应用程序增加 Web 浏览功能,如图 14 所示。
![](http://www.microsoft.com/china/msdn/library/langtool/vs2005/art/SmartClients_fig14.gif)
图 14 作用中的 WebBrowser 控件
导航到 URL 就像调用 WebBrowser 的 Navigate 方法那样简单:
void goButton_Click(object sender, EventArgs e) { // 导航到 URL this.webBrowser.Navigate(this.urlTextBox.Text); }
当 WebControl 导航到新页面时,它会先激发 Navigated 事件,然后再开始下载页面。WebControl 还会激发 ProgressChanged 事件,通过该事件可以监控页面下载进度。当然,WebBrowser 还提供了可以处理任何浏览器中都会提供的若干标准导航选项的方法:
this.webBrowser.GoBack(); // 导航到历史记录中的上一页面 this.webBrowser.GoForward(); // 导航到历史记录中的下一页面 this.webBrowser.Stop(); // 停止加载当前页面 this.webBrowser.Refresh(); // 重新加载当前页面 this.webBrowser.GoHome(); // 导航到主页
BackgroundWorker 组件
Windows Forms 应用程序经常需要执行长时间的后台操作(如搜索)。其解决方案是在 .NET 中使用多线程支持来衍生一些工作线程,通过异步方式来执行长时间运行的操作,这样主 UI 线程可以继续响应用户请求。但为工作线程编写代码可能是一项艰巨而又耗时的工作。
不过,在 Windows Forms 2.0 中,可以使用 BackgroundWorker,它将复杂的工作线程创建和管理整合在一个组件中,可以将其拖动到 Visual Studio 中的窗体上。调用 BackgroundWorker.RunWorkerAsync 会导致工作线程引发 BackgroundWorker.DoWork 事件,可以通过处理该事件来执行长时间运行的操作代码。图 15 中的代码显示了 RunWorkerAsync 和 DoWork。
BackgroundWorker 可确保在 UI 和工作线程间传递的数据以线程安全的方式进行。BackgroundWorker 也支持进度报告和取消,并且由于其为组件,因此可以通过设计器配置此功能。
自动完成
有一项改进是在若干个控件上进行的,那就是自动完成。ComboBox、TextBox、ToolStripComboBox 和 ToolStripTextBox 上都实现了这项改进。它由下面三个属性组成:AutoCompleteMode、AutoCompleteSource 和 AutoCompleteCustomSource。通过使用 AutoCompleteMode,可以设置同名枚举的自动完成样式:
enum AutoCompleteMode { None = 0, // 不自动完成(默认值) Suggest = 1, // 可能的匹配项从下拉列表中选择 Append = 2, // 可能的匹配项附加在所键入文本后面 SuggestAppend = 3 // AutoSuggest 和 AutoAppend 相结合 }
除“None”选项外,其余选项均要求将 AutoCompleteSource 属性设置为 AutoCompleteSource 枚举所指定的几个系统自动完成来源之一:
enum AutoCompleteSource { FileSystem = 1, // 文件系统 HistoryList = 2, // 历史记录列表中的所有 URL RecentlyUsedList = 4 // 最近使用列表中的所有 URL AllUrl = 6, // HistoryList + RecentlyUsedList AllSystemSources = 7, // FileSystem + AllURL FileSystemDirectories = 0x20, // 文件系统文件夹 CustomSource = 0x40, // AutoCompleteCustomSource None = 0x80, // 无来源(默认值) ListItems = 0x100 // 控件列表(仅限组合框)中的项目 }
如果选择 CustomSource,即是指示 ComboBox 您将通过存储在 AutoCompleteCustomSource 属性中的项目集合提供自动完成选项。ListItems 将来源指定为存储在 ComboBox List 属性中的项目。
条形控件
值得特别提及的是条形控件,这是因为它们有着酷炫的外形。MenuStrip、ToolStrip、StatusStrip 和 ContextMenuStrip 为用户界面增添了一股现代气息,如图 16 中所示。
![](http://www.microsoft.com/china/msdn/library/langtool/vs2005/art/SmartClients_fig16.gif)
图 16 条形控件
新条形控件接替了 MainMenu、ToolBar、StatusBar 和 ContextMenu(在 Windows Forms 2.0 中得到了保留,以保持向后兼容性),并在它们的基础上进行了若干个方面的改进,其中包括:
• |
所有条形控件使用一致的 API |
• |
改进了设计时体验 |
• |
可以在窗体边缘之间拖动 |
• |
具有 Office 2003 和 Windows 主题相关性 |
• |
可以驻留一组丰富的子控件,其中包括下拉列表、标签、菜单和文本框 |
• |
简化了自定义绘制支持 |
• |
与设置系统集成 |
• |
与 MainMenuStrip 属性进行了窗体集成,与 ContextMenuStrip 属性进行了控件集成 |
条形控件提供了大规模的设计时支持,其中最重要的支持是简化了向每个条形控件添加项目的过程。可以添加到条形控件中的项目取决于条形控件的用途,如图 17 所示。
可以通过 Properties(属性)窗口使用智能标记来添加、更新和删除条形控件项目,也可以通过设计图面直观地添加、更新和删除条形控件项目。MenuStrip 和 ToolStrip 都提供了“Insert Standard Items(插入标准项目)”选项,以使用“打开”、“保存”、“另存为”、“剪切”、“复制”和“粘贴”这类典型命令所对应的项目预填充控件。
通过条形控件 Properties(属性)窗口和智能标记,可以进行各种其他值得注意的配置,其中最重要的配置由图 18 中所列的属性来控制。除了通常可以在控件上看到的标准属性(如 Enabled、Visible、Checked 和 BorderStyle)外,条形控件还提供了一些附加属性,如图 19 所示。
条形容器
条形控件套件的主要特色之一是,可以将条形控件从窗体的一个边缘拖动到另一个边缘。尽管默认情况下条形控件停靠在窗体边缘,但停靠并不提供支持拖动所需的智能。这种行为实际上是通过 ToolStripContainer 控件添加到窗体中,如图 20 所示。
![](http://www.microsoft.com/china/msdn/library/langtool/vs2005/art/SmartClients_fig20.gif)
图 20 ToolStripContainer 控件
因为 ToolStripContainer 是一种提供窗体范围条形控件语义的容器控件,所以需要在添加任何其他控件之前先将它添加到窗体中。控件随后将添加到其内容面板,而条形控件将添加到四个特殊面板中的一个。可以展开或折叠每个面板,以适应您想要放置在各窗体边缘的条形控件。通过设置 ToolStripContainer 的 TopToolStripPanelVisible、RightToolStripPanelVisible、BottomToolStripPanelVisible 和 LeftToolStripPanelVisible 布尔属性,还可以根据需要隐藏/显示面板。
运行时,可以在窗体的边缘之间拖动条形控件,其对应的面板会显示出来。只可以拖动具有拖动柄的条形控件。而且,如果有两个或更多个工具条形控件位于同一工具条形面板中,用户可以根据需要调整这些控件的位置。因为用户可以在运行时将工具条移动到新位置,所以用户希望在结束一个应用程序会话并启动下一个应用程序会话时,工具条仍在那些位置。因此,需要使用 ToolStripManager 类(来自 System.Windows.Forms),该类很好地实现了静态(共享)LoadSettings 和 SaveSettings 方法。
数据绑定
在 Windows Forms 2.0 中,由于新 BindingSource 组件的主要作用是升级不具有数据绑定功能的数据源,使其具有更丰富的数据绑定功能,因此数据绑定功能比以前丰富得多。这样就可以统一异构数据源,还可以简化针对任何类型数据源创建单一客户端代码模式的过程。
![](http://www.microsoft.com/china/msdn/library/langtool/vs2005/art/SmartClients_fig21.gif)
图 21 数据源
通过使用 Data Source Configuration Wizard(数据源配置向导)(Data(数据)| Add New Data Source(添加新数据源)),可以轻松地将数据源添加到项目中。可以在其中为数据库、Web 服务和对象创建数据源。如果通过数据库创建数据源,新的强类型化 DataSet 将添加到项目中,并可以通过新的 Data Sources(数据源)窗口(Tools(工具)| Data(数据)| Show Data Sources(显示数据源))查看它,如图 21 所示。
Data Sources(数据源)窗口提供了用于添加新数据源的工具条项目,如果数据源是强类型化 DataSet,则还会提供用于编辑、重新配置或刷新它们的工具条项目。拖放到窗体上时,像 DataGridView 这样的控件将自动提示您选择数据源或创建一个新数据源。
BindingSource
提到“数据源”,您想到的可能是最常见的类型:类型化 DataSet。但数据源的形式和大小多种多样,其中包括表、XML 和基于 .NET 的对象。在 Windows Forms 1.x 中,可以绑定到所有上述数据源,但数据绑定集成的程度有差异。这使开发人员不得不花费不少的时间来更新其数据源,以通过实现 IBindingList 来达到更高程度的数据源绑定集成。Windows Forms 2.0 BindingSource 组件解决了这一问题,它能够使用任何列表类型并将这些类型作为 IBindingList 列表数据源实现来重新提供。此外,还可以将项目类型传递给 BindingSource 组件,该组件会自动将这些项目类型转换为 IBindingList 实现。
要配置 BindingSource 以使用所需的数据源,请将一个 BindingSource 拖动到窗体上,根据需要设置它的 DataSource 和 DataMember 属性。以下是使用类型化 DataSet 的 BindingSource 的示例:
public partial class DataBindingForm :Form { public DataBindingForm() { ... // 使用类型数据集 this.bindingSource.DataSource = this.northwindDataSet; this.bindingSource.DataMember = "Employees"; } }
BindingSource 组件此时提供强类型化 DataSet 作为控件可以绑定到的数据源。
DataGridView
Windows Forms 团队借此机会构建了一个全新的网格控件 System.Windows.Forms.DataGridView,以响应开发人员社区关于 DataGrid 的反馈。(DataGrid 得到保留,用于导航和编辑分层数据。)
DataGrid 与 DataGridView 之间的一个显著差异是后者的对象模型,该模型在进行抽象化处理后成为了由列、行和单元格组成的自然网格结构,如图 22 所示。开发人员通过这个自然网格结构可以快速地按照逻辑关系深入了解众多位于直观位置的功能,其中包括:
• |
通过样式、格式设置、布局和项目选择支持丰富的 UI 自定义 |
• |
原生显示比 DataGrid 范围更广的各种数据类型(包括图像)的功能 |
• |
诸如列冻结和运行时列重新排序等一流功能 |
• |
100 多个事件,用于精确控制导航、编辑、验证、自定义绘制和错误处理 |
![](http://www.microsoft.com/china/msdn/library/langtool/vs2005/art/SmartClients_fig22.gif)
图 22 DataGridView 对象模型
其中一个新功能是单击单元格时选择行,该功能通过 DataGridView 的 SelectionMode 属性来配置。当然,没有任何控件可以满足所有人的任何需要。有这种需要时,开发人员可以依靠扩展功能来引入自定义功能。DataGridView 基础结构提供了可以作为派生来源和插件的各种单元格、行和列基本实现,其中包括 DataGridViewColumn 和 DataGridViewCell。所有这些都使 DataGridView 成为了比 DataGrid 吸引力大得多的网格样式控件。
填充 DataGridView 的最常见方法是将其绑定到数据源,通过将其 DataSource 属性设置为 BindingSource 可实现此目的,如图 23 所示。
![](http://www.microsoft.com/china/msdn/library/langtool/vs2005/art/SmartClients_fig23.gif)
图 23 将 DataGridView 绑定到 BindingSource
尽管 DataGridView 显示了多个项目,但有时每次只需要查看一个项目。在这种情况下,可以同样轻松地将 TextBox 这样的控件绑定到 BindingSource。但如果需要每次查看一个项目,就需要一种方法能够让用户在各个项目之间导航。这种支持通常由 VCR 样式的控件提供。您不需要自行创建该控件,而是可以将 BindingNavigator 拖动到窗体上,并将其绑定到您的控件绑定到的同一 BindingSource。BindingNavigator 还提供了当前项目和项目总数的计数信息,并且支持将项目添加到数据源及从数据源删除项目。
拖放式数据绑定
拖放控件和组件,然后编写代码来将它们连接起来似乎与数据绑定能够提高效率这个观点相左。实际上并不需要手动拖放,然后配置 UI,而是可以将数据源从 Data Sources(数据源)窗口拖放到窗体上,让 Windows 窗体设计器为您创建和配置绑定的 UI。
拖放数据源时,Windows 窗体设计器会执行下列操作:
• |
为该数据源添加 BindingSource |
• |
根据需要添加强类型化 DataSet 和表适配器 |
• |
添加绑定到 BindingSource 的必需控件,从而为这些控件提供合理的名称(DataGridView 列除外) |
• |
添加绑定到 BindingSource 的 BindingNavigator |
还可以配置放置的数据源创建 DataGridView-UI 还是 Details-UI,以及在这两种情况下生成哪些控件来满足需要。
ClickOnce 部署
最后,应用程序需要进行部署。尽管安装应用程序或 Microsoft Installer (MSI) 文件都是不错的部署技术,但需要将它们分配到客户端上并要在客户端上执行它们,并且需要使完成的安装保持最新状态。这项工作可能会很艰巨。Web 应用程序具有一个出色的部署模型:用户不必执行任何操作就可使应用程序始终是最新版本。
优良的技术会借鉴其他技术的长处;出色的技术则会用心地巧取其精髓。Windows Forms 1.x 采用了称为“无触式部署”(NTD) 的技术,该技术借鉴了 Web 部署模型的优点,可以通过它从 URL 或 UNC 文件路径部署 Windows Forms 应用程序,并且可以在受代码访问安全性 (CAS) 控制的客户机上的沙箱内执行应用程序。在 Windows Forms 2.0 中,NTD 已经发展成为 ClickOnce 部署,从而能够为 Windows Forms 应用程序提供 Web 样式部署模型。ClickOnce 提供了下列功能:
• |
•涵盖已部署应用程序创建、发布和管理的丰富配置功能 |
• |
具有多个发布位置,包括 Web 服务器、FTP 服务器、文件共享以及 CD 和 DVD 这样的媒体 |
• |
超链接样式应用程序启动 |
• |
两种安装模式:联机和联机/脱机;在后一种模式下,在用户机器上缓存 ClickOnce 应用程序后,不需要建立网络连接就可以启动该应用程序 |
• |
控制与客户端(包括“开始”菜单以及“添加/删除程序”控制面板)集成的程度 |
• |
选择安装的必备软件,如 .NET Framework 2.0(通过 Prerequisites(必备软件)按钮) |
• |
文件和程序集依赖关系管理 |
• |
设置各种发布详细信息(包括发布者详细信息)、支持 Web 页和部署 Web 页,ClickOnce 可以自动生成这些内容 |
• |
使用发布版本号,可以创建针对各种方案的版本控制策略 |
• |
围绕代码签署构建的可靠的部署和执行模型,以及完全用户驱动的 CAS |
• |
与 Visual Studio 完整集成 |
设计时,可以在 Visual Studio 中通过项目属性页面的 Publish(发布)选项卡配置 ClickOnce 部署,如图 24 所示。发布应用程序时将会应用这些不同配置的集合。
![](http://www.microsoft.com/china/msdn/library/langtool/vs2005/art/SmartClients_fig24.gif)
图 24 配置 ClickOnce 部署
发布
发布应用程序的最简单方法是:在 Solution Explorer(解决方案资源管理器)中右键单击项目,然后选择 Publish(发布),随即会打开 Publish Wizard(发布向导),向您收集各种详细信息,其中包括发布位置和安装模式。
发布应用程序时,Visual Studio 和 ClickOnce 会根据您的配置准备安装软件包,并将其复制到发布位置。ClickOnce 会生成一个文件夹,其名称是应用程序名称与发布的版本号的结合体。该文件夹包含主要应用程序程序集及任何其他依赖的文件。发布到具有不允许上载常见可执行文件类型(.exe、.dll)策略的 Web 服务器时,每个文件都将添加后缀“.deploy”。为存储构成安装软件包的文件,ClickOnce 会生成一个应用程序清单 (.manifest),该清单也会收集您在 Visual Studio 进行的各种配置。
因为可能存在多个已发布应用程序版本,所以用户需要一种方法来确定要下载的版本。出于这一目的,ClickOnce 会生成一个部署清单 (.application) 并将其添加到已发布应用程序的根目录,如图 25 所示。
![](http://www.microsoft.com/china/msdn/library/langtool/vs2005/art/SmartClients_fig25.gif)
图 25 ClickOnce 已发布应用程序
将会生成两个部署清单,一个用于最新发布的版本,另一个用于特定版本。在根目录下,将会创建一个安装应用程序,供用户在缺少任何必备软件(如 .NET Framework 2.0)时执行,并会创建一个默认 Web 页,用户可以浏览到该 Web 页并通过它启动已发布应用程序。要启动应用程序,用户可以单击 Install(安装)按钮,该按钮是最新版本应用程序清单的超链接。
安全性
启动应用程序后,ClickOnce 首先会下载清单,以确定是否可以在无需用户干预的情况下安全地下载和执行应用程序。如果发现安全性问题,将通过 Security Warning(安全警告)对话框指出。如果存在任何安全性问题,用户可以选择继续安装应用程序或放弃安装。通过单击“More Information(详细信息)”链接来查看安全性问题的详细信息,可以帮助用户做出决定。
ClickOnce 将其警告分为四个类别:“发布者”、“机器访问权限”、“安装”和“位置”。“发布者”是指发布应用程序的人员。要使 ClickOnce 将发布者视为是安全的,该发布者需要使用 Verisign 这样的认证机构发放的数字证书来签署其代码。可以通过 Visual Studio 中项目属性页面的 Signing(签名)选项卡签署应用程序。可以通过此选项卡从证书存储区或文件导入证书、创建测试证书、指定证书到期的时间戳服务器以及签署或延迟签署程序集。
“机器访问权限”是指在客户机上执行应用程序所需的权限。ClickOnce 应用程序的权限由 .NET CAS 管理,.NET CAS 会将执行中的以 .NET 为目标的应用程序封装在一个安全沙箱中,该沙箱只允许将权限授予这些应用程序。当所需权限超出从同一区域(启动 ClickOnce 应用程序的区域)启动的应用程序所允许的权限时,ClickOnce 会通过添加标记来发出安全警告。如果用户选择安装的应用程序的权限要求过高,CAS 会将这些权限授予应用程序,这一过程称作权限升级。可以通过项目属性页面的 Security(安全性)选项卡管理应用程序的权限要求,如图 26 所示。
![](http://www.microsoft.com/china/msdn/library/langtool/vs2005/art/SmartClients_fig26.gif)
图 26 ClickOnce 安全性设置
可以通过 Security(安全性)选项卡指定完全信任或部分信任,如果指定的是后者,则可以手动选择所需权限的子集,或让系统自动为您计算。也可以选择目标区域的默认权限并根据需要进行更改。可以调试应用程序,就好像是从指定区域部署应用程序并被限定为只具有指定的权限。
总结
我们介绍了许多内容,浏览了 Windows Forms 2.0 的一些主要新增功能。对此不感到兴奋是困难的,当您想到全年 MSDN®Magazine 的所有版面都不足以详细介绍所有这些新功能时,就更是如此。不过,我们向您介绍了内容更丰富而且功能更强大的 .NET Framework、新的控件和组件、改进的数据绑定、ClickOnce 部署以及与 Visual Studio 的丰富集成,这些内容无疑很适合作为您着手研究的对象。熟悉 Windows Forms 2.0 之后,您就会发现可以在比以往都要短的时间内构建具有更多功能的 Windows Froms 应用程序,Windows Forms 2.0 所采用的技术在未来的许多年中都将是旗舰 Windows 应用程序开发平台。
Chris Sells 是 Microsoft 连通系统部门的程序经理,从事下一代应用程序开发技术的研究工作。可以在 http://www.sellsbrothers.com/ 中找到有关 Chris 和他参与的各个项目的详细信息。
Michael Weinhardt 目前正在与他人合作更新 Windows Forms Programming in C#(作者:Chris Sells,Addison-Wesley Professional 2003 年出版),并为称作 Wonders of Windows Forms 的 MSDN Online 编写每月专栏文章。有关详细信息,请访问 http://www.mikedub.net/。
http://www.microsoft.com/china/msdn/library/langtool/vs2005/SmartClients.mspx?pf=true