利用.NET Framework创建基于Windows的应用程序

摘要:这篇文章介绍了一种全新的窗体形式━━Win Form,它可以使开发人员充分利用 微软 的Windows 操作系统 中提供的UI功能。

   介绍

  由当前关于互联网的许多讨论来看,似乎微软的Visual Studio开发系统已经完全不再支持开发传统的基于Windows操作系统的应用程序了。而实际情况是,微软依然非常重视对基于Windows的应用程序的开发。

  Win Forms是一种全新的窗体形式,开发人员可以利用它创建充分利用微软的Windows操作系统中丰富的用户接口的应用程序。Win Forms是微软的.NET平台的一部分,采用了许多新的技术,包括一个公共应用程序框架、可管理的执行环境、集成的 安全 性和面向对象的 设计 原则。此外,Win Forms还提供了对方便迅速连接到互联网服务和创建基于ADO+数据模型的应用程序的支持。有了Visual Studio中全新的共享开发环境,开发人员就能够使用包括Visual Basic和C#在内的任何支持.NET平台的编程语言开发基于Win Forms的应用程序。

   Win Forms是什么?

  就象在上面提到的那样,Win Forms是.NET Framework中专指Windows客户端UI编程的名字空间,它与被称作Web Forms的ASP+ UI的设计原理相同,但其中的类和具体的实现是完全不同的,Win32 API和Web组件之间的类是不能够互相转换的。然而,象.NET框架中的其他部分一样,一致性是其最优先考虑的部分,目的是让一个Win Forms开发人员能够迅速地适应Web Forms的编程方式,反之亦然。例如,二个名字空间都有Button类,其中都有文本域、OnClick事件和ForeColor、BackColor、Font等属性。

  Win Forms控制是完全基于System.WinForms.Control类的,Control类有基本的HWND功能,处理大部分常见的WM_xxxx消息。从Control类派生出的是RichControl控制,它添加了输出逻辑和绘制代码,System.WinForms名字空间中的大部分控制都是由继承RichControl得来的。ScrollableControl添加了对窗口用户区滚动的支持。一般情况下,滚动支持是通过ContainerControl控制获得的,ContainerControl控制是由继承

  ScrollableControl控制而得来的,其中添加了对子控制、焦点和标签进行管理的支持。由继承ContainerControl而生成的是Form,它是Win Form的最高层的控制,它有控制标题条、系统菜单、不规则窗口和缺省控制的属性。另一个由继承ContainterControl而生成的是UserControl,它就是开发人员可以创建的控制的基本类。UserControl是用来管理其他子控制的。微软的Visual Studio .NET中有可视化的UserControl和Form设计器,我们可以发现用来添加和设计由继承它们生成的类的工程条目。 


  我们已经讨论了有关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是一种安全函数的指针,可以为任何控制的任何事件添加Delegate事件自理程序,我们也无需通过重载创建一个处理所有事件的类,创建一个事件图,或者为一个类中的所有事件实现一个接口而只会执行其中的一个。事件也可以通过重载继承类进行处理,但一般情况下只有控制的创建者和在高级的应用程序设计中才会这样作。接收一个按钮的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框架应用程序和C/C++应用程序在复杂性方面的判别就会越来越明显。由于信息只包含在代码文件中,在Visual Studio .NET环境之外创建工程也是相当简单的,而无论是Visual Basic代码、C#代码或是其他任何支持.NET框架的语言写成的。

  由于Win Forms是建立在通用语言运行库的,因此开发人员可以选择任何一种支持通用语言运行库的编程语言开发Win32应用程序。开发人员可以使用从C#到COBOL、Eiffel、Perl在内的17种编程语言开发Win Forms应用程序(或者Web Forms应用程序和Data应用程序),这使得掌握多种编程语言的开发人员可以高效地使用Win Forms建立应用程序。

 

输出布局

  如果你曾经尝试着创建一个能够正确地改变大小的窗体,就会发现这是多么困难了/MFC和以前的Visual Basic没有对此提供任何内置的支持。但在Visual Studio .NET中仅仅需要几行的代码(甚至这些代码不需要你动手编写,因为在设计窗体时的Property Browser(属性浏览器)中就能实现这样的功能。),就能创建一个能够正确地改变大小的对话框。

  基本的输出布局是由二部分组成的:Anchoring和Docking。RichControl类有一个Anchor属性,这是一个枚举型变量的值通过或运算来描述一个控制与其父控制边缘的距离。例如,如果在一个窗体上创建了一个按钮,并且将其Anchor属性设置为AnchorStyles.BottomRight,则在改变大小时,按钮将与窗体的下、右边缘保持相同的距离。如果将Anchor属性设置为AnchorStyles.All,按钮将与窗体的四周保持固定的距离,按钮就会改变自己的大小来符合这一要求。

  Docking是Anchoring的一种特殊情况。RichControl的Dock属性定义控制与父控制的哪个边相接触,它的值可以是Top、Left、Right、Bottom或Fill。当父控制的大小变化时,它将仍然维持与特定边缘的距离。将一个控制移动到移动到父控制的底部,并将Anchor设置为AnchorStyle.BottomLeftRight,等同于将Dock属性设置为Bottom。在本例中,列表框与窗体的左边缘相接触,按钮与窗体的顶、左和右边保持一定的距离,因此,它们能够维持相对的位置和大小。下面例子中对话框(图2)是使用Visual Studio .NET中的Win Forms Designer设计的。在创建它时我用了2分钟的时间,而没有编写一行代码:



// ResizableSample.cs
namespace ResizableSampleNamespace {

using System;
using System.Drawing;
using System.ComponentModel;
using System.WinForms;

///
/// Summary description for ResizableSample.
///
public class ResizableSample : System.WinForms.Form {
///
/// Required by the Win Forms designer 
///
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 Designer要求下面的初始化函数
 InitializeComponent();

}

///
/// 清除所使用的资源文件
///
public override void Dispose() {
 base.Dispose();
 components.Dispose();
}


///
/// 应用程序的主入口
///
public static void Main(string[] args) {
 Application.Run(new ResizableSample());
}


///
/// Designer所需要的方法不要使用编辑器编辑其中的内容 
///
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充分利用了微软新一代的2D图形系统GDI+。Win Forms中的图形编程模式是完全面向对象的,而且有与.NET Framework中其他部分同样易用的Pen、Brushe、和Images等对象,开发人员可以使用α混合、色彩渐变、材质、抗失真和其他图象格式而不是仅仅能够使用位图,与Windows 2000中分层、透明的窗口功能相结合,开发人员可以更简单地创建更丰富的Win32应用程序。

  当一个对象的OnPaint事件运行时,从PaintEventArgs中可以访问的System.Drawing.Graphics对象是一个GDI+图形对象,图形对象能够完成的所有操作都通过GDI+执行。在下面的例子中,我们使用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;
 }

 ///
 /// 渐变色彩中最后的颜色
 //
 public Color EndColor {
  get {
   return this.endColor;
 }
 set {
  this.endColor = value;
  // 如果需要重新绘制
  if (this.IsHandleCreated && this.Visible) {
   Invalidate();
  }
 }
}


///
/// 渐变色彩中的起始色彩
//
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);
 }
}


  就象我们在例子中已经看到的那样,使用GDI+并不特别困难。Win Forms和GDI+中面向对象的设计使得我们无需使用任何复杂的代码就能实现GradientButton,Text、Font、StartColor和EndColor等属性可以通过Property Browser进行操作。

 底层系统的访问

  对于创建样例和演示中所示类型的应用程序而言,.NET框架确实很棒,但开发人员发现,在使用.NET框架编程时,在一些特定的情况下会有困难。在遇到类似的困难时,Win Forms框架允许开发人员访问系统底层。所有的控制都有一个可以访问控制窗口句柄的Handle属性,GDI对象也有类似的句柄访问功能。而且,控制都有一个属性为protected virtual的WndProc方法,该方法可以被我们编写的其他方法覆盖,处理Win Forms不支持的一些消息的处理。


  例如,如果应用程序对资源的要求比较高,就需要响应WM_COMPACTING消息。如果系统的内存不足,就会向所有的顶层窗口广播WM_COMPACTING消息。Win Forms没有提供对这一消息进行处理的内置功能,我们可以添加下面的代码,为它添加支持这一消息的能力:

///
///Win32Form1的定义
///
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类而生成的类就会得到通知,并对系统发出的信息进行响应。

   结论

  尽管面向互联网的开发已经成为许多开发人员计划中的重中之重,但我们熟悉的Win32平台仍然具有很大的吸引力。使用Win Forms,Windows编程的菜鸟和大虾们将会发现可以使用.NET Framework中丰富的接口和许多互联网、数据技术很方便地创建具有复杂功能的应用程序。

  通过利用跨平台的继承性、碎片收集和安全性等通用语言运行库提供的功能强大的功能,开发人员将受益于.NET Framework和Win Form。

 

原文来自:天极网。

你可能感兴趣的:(.NET,专区)