我们已经讨论了有关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); } } |
底层系统的访问
对于创建样例和演示中所示类型的应用程序而言,.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); } } |
原文来自:天极网。