分享
 
 
 

使用 Microsoft.NET Frameworks 创建Windows应用程序

王朝c#·作者佚名  2006-01-08
窄屏简体版  字體: |||超大  

使用 Microsoft.NET Frameworks 创建基于 Windows 的应用程序Shawn Burke

Microsoft Corporation

2000年9月

摘要: :本文介绍了 Win 表单这一新的窗体程序包,借助这一程序包,开发人员能够充分利用 Microsoft Windows 操作系统所提供的 UI 功能。

目录

简介

介绍 Win Forms

更好的易学易用性

布局

GDI+

访问底层系统

结论

简介

目前 Web 已成了街谈巷议的话题,看起来好像 Microsoft® Visual Studio® 开发系统对创建基于 Microsoft Windows® 的传统应用程序的支持有所减弱。实际上,Microsoft 对基于 Windows 的应用程序开发方面的投资在不断加大。

Win 表单是一个新的窗体程序包,借助这一程序包,开发人员能够充分利用 Microsoft Windows® 操作系统所提供的丰富的用户界面功能,创建基于 Windows 的应用程序。Win Forms 是新的 Microsoft®.NET 平台的一个组成部分,它提供了许多新技术,包括通用的应用程序框架、可管理的执行环境、一体化的安全性以及面向对象的设计原则。而且,Win Forms 全面支持快速简便地接入 Web Services 以及建立丰富的基于 ADO+ 数据模型的数据感知应用程序。得益于 Visual Studio 中新的共享开发环境,开发人员能够使用包括 Microsoft Visual Basic® 和 C# 在内的任何支持 .NET 平台的语言创建 Win Forms 应用程序。

介绍 Win Forms

就像刚才所说的,Win Forms 是专用于 Windows 客户机 UI 编程的 .NET Framework 的命名空间。它与 ASP+ UI 程序包(即 Web Forms)共享同样的设计原则,但其类和实现却全然不同。在 Microsoft Win32® API 和 Web 组件之间没有魔术般变形的类。就像所有的 .NET Frameworks 一样,一致性已成为优先考虑的问题。其目的是为了 Win Forms 开发人员能够迅速适应在 Web Forms 中编写代码,反之亦然。例如,所有命名空间都有 Button 类,每一个都有文本、默认的 OnClick 事件以及 ForeColor、BackColor 和 Font 属性。

Win Forms 的所有控件都基于 System.WinForms.Control 类。Control 已内置了所有基本的 HWND 功能,并且它能处理我们已经熟悉并喜爱的绝大多数通用 WM_xxxx 消息。RichControl 由 Control 派生而来,其中添加了布局逻辑和绘图代码。System.WinForms 命名空间中的绝大多数控件实际上都由 RichControl 派生而来。ScrollableControl 能够支持窗口客户区域的滚动。一般情况下,对滚动功能的支持是通过 ContainerControl 实现的,后者由 ScrollableControl 派生而来,并增加了对管理子控件、焦点问题和跨栏的支持。Form 由 ContainerControl 派生而来,是 Win Form 的顶级控件,它带有控制标题栏、系统菜单、非矩形窗口和默认控件的属性。UserControl 也由 ContainterControl 派生而来,是开发人员能够创建的控件的基本类。UserControl 一般用于托管其它子控件,但对于外部客户机来说,它又是作为单个单元出现的。UserControl 和 Form 在 Microsoft® Visual Studio.NET 中都有可视设计器,您会找到用于添加和设计由其所派生的类的项。

图 1. Win Forms 控件层次结构

既然我们已了解 Win Forms 的(最)基本方面,让我们揭开它的面纱,看看其表面下的一些相当不错的功能。

更好的易学易用性

Win Forms 的主要目的是尽可能地提高定位到 Win32 平台的开发人员的工作效率。无论是图形设备界面 (GDI) 还是窗口状态管理,为 Win32 编程通常都是很困难的。例如,类似 WS_BORDER 或 WS_CAPTION 的一些窗口样式只能在创建窗口时指定或修改。而 WS_VISIBLE 或 WS_CHILD 等其它窗口样式则可以对已创建的窗口进行修改。Win Forms 尽力消除了这些细微的差别,并确保操作过程始终保持一致性。可以随时地、不限次序地对 Win Forms 控件的属性进行设置,总能产生预期效果。如果改动过程需要创建新的 HWND,Win Forms 框架能够自动地、透明地重新生成窗口,并为其应用相适宜的所有设置。

由控件获得通知或事件在 Win Forms 中也要容易得多。Win Forms 事件都基于称为 Delegates 的一个通用语言运行时功能。Delegates 从本质上讲是对类型安全的、可靠的函数指针。对于任一控件的任一事件,都可以添加代理处理程序;绝不会强迫您创建派生类以通过替代处理事件,创建事件映射,或仅为处理一个事件而为类的所有事件实施一个接口。也可以通过替代派生类处理事件,但这种方式一般用于控件创建者或更为高级的应用。汇集某一按钮的 Click 事件相当简单:

public class ButtonClickForm: System.WinForms.Form {

private System.WinForms.Button button1;

public ButtonClickForm() {

// 创建按钮

button1 = new System.WinForms.Button();

// 添加处理程序

button1.AddOnClick(new System.EventHandler(button1_Click));

// 将按钮添加到窗体中

this.Controls.Add(button1);

}

private void button1_Click(object sender, EventArgs e) {

MessageBox.Show("button1 clicked!");

}

}

这里,我们创建了一个按钮,并添加了一个名为 button1_Click 的处理程序方法,通过短短几行代码,在单击该按钮后,将调用这一方法。请注意,即使处理程序方法被标记为专用,创建这一挂钩的代码仍可以使用该方法,单击按钮后,按钮将能够激活这一方法的事件。

启动 Win Forms 项目的过程也得到了简化。使用 Visual Studio.NET 创建 Win Forms 项目的过程只会创建一个要编译的项目文件:Form1.cs。没有头文件,没有接口定义文件,没有引导程序文件,没有资源文件,没有库文件。项目所需的所有信息都包含在窗体的代码中。这样做有一个好处:项目由一个简单的单窗体应用程序扩展到复杂的、带有多个代码文件的多窗体应用程序要方便得多。链接过程不需要中间对象文件,只有代码和已构建的、受管理的所有 DLL。只要您习惯了这一方法,就能明显地感觉到创建 .NET Framework 应用程序和创建 C/C++ 应用程序之间复杂性的不同。因为信息仅仅包含在代码文件中,在 Visual Studio.NET 环境外创建版本的过程也非常容易,无论是 Visual Basic 代码、C# 代码,还是任何其它语言编写的针对 .NET Framework 的代码。

因为 Win Forms 建立在通用语言运行时的基础之上,开发人员可以任选目前针对通用语言运行时的众多语言中的一种,构建 Win32 应用程序。开发人员现在可以使用多种语言编写 Win Forms 应用程序(或 Web Forms 应用程序或 Data 应用程序):从 C# 到 COBOL 到 Eiffel 再到 Perl 等等,中间还有很多种(上一次计数是 17 种)。方便易用再加上广泛的应用场合相得益彰,为开发人员提供了深厚的基础,使他们能够迅速有效地使用 Win Forms 构建实用的应用程序。

布局

如果您曾尝试创建能够正常调整大小的窗体,您就会知道这一过程有多么困难。Microsoft Foundation Classes (MFC) 或早期的 Visual Basic 版本没有对这一功能提供内置的支持。然而现在只需几行代码(通常情况下您甚至不需要编写这些代码,因为在设计时就能通过 Property Browser 实现这些功能!),即可创建能够正常调整大小的对话框。

基本布局由两条组成:Anchoring 和 Docking。RichControl 有一个 Anchor 属性,它是一种枚举类型,可以用“或”操作将这些值组合在一起,以说明控件将与其父控件的某一边保持恒定距离。例如,如果您将一个按钮置于窗体上,并将 Anchor 属性设置为 AnchorStyles.BottomRight,则在调整按钮的大小时,按钮将与窗体的底边和右边保持同一距离。此外,如果将 Anchor 设置为 AnchorStyles.All,则按钮的各个边都与窗体的对应边保持同一距离,在调整按钮大小时仍要满足这些约束条件。

Docking 实际上是 Anchoring 的一个特殊情况。RichControl 的 Dock 属性说明控件要将自身固定到其父控件的哪一边。Docking 可以是 Top、Left、Right、Bottom 或 Fill。在每种情况下,控件都将移动到尽量靠近指定边,并调整其大小,以填满那一边。如果父控件的大小有所调整,这一状况仍将保持。将一个控件移动到父控件的底端,并将 Anchor 设置为 AnchorStyle.BottomLeftRight,可以模拟 Docking Bottom。在此处的示例中,列表框是 Docked Left,按钮与窗体的顶端、左边和右边保持恒定距离,由此它们保持了相对位置和大小。下面的示例对话框(图 2)完全使用 Visual Studio.NET 中的 Win Forms 设计器创建,只花了两分钟的时间,没有编写一行代码。

图 2. 使用 Win Forms 设计器所创建的可调整大小的对话框

// ResizableSample.cs

namespace ResizableSampleNamespace {

using System;

using System.Drawing;

using System.ComponentModel;

using System.WinForms;

/// <summary>

/// ResizableSample 的摘要说明。

/// </summary>

public class ResizableSample : System.WinForms.Form {

/// <summary>

/// 为 Win Forms 设计器所要求

/// </summary>

private System.ComponentModel.Container components;

private System.WinForms.Button button3;

private System.WinForms.Button button2;

private System.WinForms.Button button1;

private System.WinForms.ListBox listBox1;

public ResizableSample() {

// 为 Win Form 设计器支持所要求

InitializeComponent();

}

/// <summary>

/// 释放正在使用的所有资源

/// </summary>

public override void Dispose() {

base.Dispose();

components.Dispose();

}

/// <summary>

/// 应用程序的主入口点。

/// </summary>

public static void Main(string[] args) {

Application.Run(new ResizableSample());

}

/// <summary>

/// 设计器支持所要求的方法 — 不要用编辑器

/// 修改这一方法的内容

/// </summary>

private void InitializeComponent()

{

this.components = new System.ComponentModel.Container();

this.button2 = new System.WinForms.Button();

this.button3 = new System.WinForms.Button();

this.button1 = new System.WinForms.Button();

this.listBox1 = new System.WinForms.ListBox();

//@design this.TrayLargeIcon = false;

//@design this.TrayHeight = 0;

this.Text = "Resizable Dialog";

this.IMEMode = System.WinForms.IMEMode.Off;

this.AutoScaleBaseSize = new System.Drawing.Size(5, 13);

this.ClientSize = new System.Drawing.Size(256, 173);

button2.Location = new System.Drawing.Point(152, 60);

button2.Size = new System.Drawing.Size(92, 32);

button2.TabIndex = 2;

button2.Anchor = System.WinForms.AnchorStyles.TopLeftRight;

button2.Text = "Cancel";

button3.Location = new System.Drawing.Point(152, 120);

button3.Size = new System.Drawing.Size(92, 44);

button3.TabIndex = 3;

button3.Anchor = System.WinForms.AnchorStyles.All;

button3.Text = "Filler";

button1.Location = new System.Drawing.Point(152, 8);

button1.Size = new System.Drawing.Size(92, 32);

button1.TabIndex = 1;

button1.Anchor = System.WinForms.AnchorStyles.TopLeftRight;

button1.Text = "OK";

listBox1.Size = new System.Drawing.Size(120, 173);

listBox1.Dock = System.WinForms.DockStyle.Left;

listBox1.TabIndex = 0;

listBox1.Items.All = new object[] {"Item One",

"Item Two",

"Item Three",

"Item Four"};

this.Controls.Add(button3);

this.Controls.Add(button2);

this.Controls.Add(button1);

this.Controls.Add(listBox1);

}

}

}

GDI+

Win Forms 全面利用了 GDI+ 这一 Microsoft 下一代的二维图形系统。Win Forms 中的图形编程模式完全是面向对象的,各式各样的画笔、笔刷、图像和其它图形对象与 .NET Framework 的其它部分一样,遵循了简单易用的指导方针。开发人员目前可以使用相当不错的一些绘图新功能,如 alpha 混色、渐变色、纹理、消除锯齿以及采用除位图外的其它图像格式。与 Windows 2000 操作系统分层和透明的窗口功能配合使用,开发人员能够毫不费力地创建丰富的、更为图形化的 Win32 应用程序。

如果触发了控件的 OnPaint 事件,能够由 PaintEventArgs 访问的 System.Drawing.Graphics 对象就成为一个 GDI+ 图形对象。图形对象能够执行的所有操作都通过 GDI+ 实施。作为一个示例,使用 GDI+ 创建一个绘制渐变背景的按钮。

图 3. 使用 GDI+ 创建的按钮

以下是实现这一按钮的代码:

public class GradientButton : Button {

// 保留颜色设置的成员

private Color startColor;

private Color endColor;

// 书写文字时我们将需要它

private static StringFormat format = new StringFormat();

public GradientButton() : base() {

// 初始化颜色

startColor = SystemColors.InactiveCaption;

endColor = SystemColors.ActiveCaption;

format.Alignment = StringAlignment.Center;

format.LineAlignment = StringAlignment.Center;

}

/// <summary>

/// 渐变色的终止颜色

// </summary>

public Color EndColor {

get {

return this.endColor;

}

set {

this.endColor = value;

// 如有必要,则导致重新绘制

if (this.IsHandleCreated && this.Visible) {

Invalidate();

}

}

}

/// <summary>

/// 渐变色的起始颜色

// </summary>

public Color StartColor {

get {

return this.startColor;

}

set {

this.startColor = value;

// 如有必要,则导致重新绘制

if (this.IsHandleCreated && this.Visible) {

Invalidate();

}

}

}

protected override void OnPaint(PaintEventArgs pe) {

// 绘制按钮的常规背景以形成

// 边框,等等。

base.OnPaint(pe);

Graphics g = pe.Graphics;

Rectangle clientRect = this.ClientRectangle;

// 缩小矩形,以免绘制时出界

clientRect.Inflate(-1,-1);

// 创建渐变笔刷,从

// 左上角运行到右下角。

Brush backgroundBrush = new LinearGradientBrush(

new Point(clientRect.X,clientRect.Y),

new Point(clientRect.Width, clientRect.Height),

startColor,

endColor);

// 以渐变色填充背景....

g.FillRectangle(backgroundBrush, clientRect);

// 在客户机区域的中间书写文字。

g.DrawString(this.Text,

this.Font,

new SolidBrush(this.ForeColor),

clientRect,

format);

}

}

就像您所看到的,这并不是非常困难。得益于 Win Forms 和 GDI+ 面向对象的设计,无需编写任何复杂的代码,即可实现我们的 GradientButton,并且在设计器中,可以通过 Property Browser 操作 Text、Font、StartColor 和 EndColor。

访问底层系统

许多框架的一个缺点就是:如果人们编写的应用程序类型与示例和演示中的严格一致,则这些框架的效果相当不错,但有时开发人员发现,一旦他们希望用框架进行一些有创造性的工作,某些情况下就会碰到障碍或遭到失败。如果遇到这一情况,Win Forms 框架自始至终都能够允许开发人员访问系统基础结构。当然,希望 Win Forms 这样一个设计优良的框架不会使用户遭遇这种情况,但可能发生的情况几乎是无限的。所有的控件都有 Handle 属性,允许访问控件的窗口句柄 (HWND),GDI 对象也提供了类似的句柄访问过程。而且,Control 实际上拥有一个名为 WndProc 的受保护的虚拟方法,对于少数 Win Forms 尚不能支持的消息,可以替代该方法,添加处理方式。

例如,假设您的应用程序是资源密集型的,需要响应 WM_COMPACTING。如果系统检测到内存不足,会向所有高层窗口广播 WM_COMPACTING,您就会知道 Win Forms 框架对这一消息没有提供内置支持,由此,可以添加如下处理过程:

/// <summary>

/// Win32Form1 的摘要说明。

/// </summary>

public class CompactableForm : System.WinForms.Form {

private EventHandler handler;

public void AddOnCompacting(EventHandler h) {

handler = (EventHandler) Delegate.Combine(handler, h);

}

protected override void OnCompacting(EventArgs e) {

// 查看运行时系统能否释放任何东西

System.GC.Collect();

// 调用任一处理程序。

if (handler != null) handler(this, e);

}

public void RemoveOnCompacting(EventHandler h) {

handler = (EventHandler) Delegate.Remove(handler, h);

}

protected override void WndProc(ref Message m) {

case (m.msg) {

case win.WM_COMPACTING:

OnCompacting(EventArgs.Empty);

break;

}

base.WndProc(m);

}

}

只需数行代码,当系统试着收集未用资源时,利用新的 CompactableForm 类或由此派生的类即可得到通知,并作出响应。

结论

尽管在许多开发人员的计划中,针对 Web 的开发是当前工作的重点,而定位于熟悉的 Win32 平台仍然是一个不得不面对的情况。有了 Win Forms,Windows 开发人员无论是新手还是老手,都会发现使用丰富的接口创建复杂的应用程序是一个很方便的过程,而这些接口与 .NET Framework 中具有 Web 和数据功能的许多技术配合良好。

通过利用跨语言继承、碎片收集和安全性等通用语言运行时提高工作效率的优秀功能,开发人员将从 .NET Framework 和 Win Forms 中获益。

 
 
 
免责声明:本文为网络用户发布,其观点仅代表作者个人观点,与本站无关,本站仅提供信息存储服务。文中陈述内容未经本站证实,其真实性、完整性、及时性本站不作任何保证或承诺,请读者仅作参考,并请自行核实相关内容。
2023年上半年GDP全球前十五强
 百态   2023-10-24
美众议院议长启动对拜登的弹劾调查
 百态   2023-09-13
上海、济南、武汉等多地出现不明坠落物
 探索   2023-09-06
印度或要将国名改为“巴拉特”
 百态   2023-09-06
男子为女友送行,买票不登机被捕
 百态   2023-08-20
手机地震预警功能怎么开?
 干货   2023-08-06
女子4年卖2套房花700多万做美容:不但没变美脸,面部还出现变形
 百态   2023-08-04
住户一楼被水淹 还冲来8头猪
 百态   2023-07-31
女子体内爬出大量瓜子状活虫
 百态   2023-07-25
地球连续35年收到神秘规律性信号,网友:不要回答!
 探索   2023-07-21
全球镓价格本周大涨27%
 探索   2023-07-09
钱都流向了那些不缺钱的人,苦都留给了能吃苦的人
 探索   2023-07-02
倩女手游刀客魅者强控制(强混乱强眩晕强睡眠)和对应控制抗性的关系
 百态   2020-08-20
美国5月9日最新疫情:美国确诊人数突破131万
 百态   2020-05-09
荷兰政府宣布将集体辞职
 干货   2020-04-30
倩女幽魂手游师徒任务情义春秋猜成语答案逍遥观:鹏程万里
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案神机营:射石饮羽
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案昆仑山:拔刀相助
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案天工阁:鬼斧神工
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案丝路古道:单枪匹马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:与虎谋皮
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:李代桃僵
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:指鹿为马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:小鸟依人
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:千金买邻
 干货   2019-11-12
 
推荐阅读
 
 
 
>>返回首頁<<
 
靜靜地坐在廢墟上,四周的荒凉一望無際,忽然覺得,淒涼也很美
© 2005- 王朝網路 版權所有