---------------------------------------------------------------------------
开发第一个Windows应用程序
在本章笔者带着读者使用VS.NET2010开发第一个Windowns应用程序。初步了解使用C#进行Windows应用开发。
本软件的功能需求就是开发一个能进行加减乘除的计算器。
建立C# Windows应用程序项目
笔者点击VS.NET开发环境的菜单“文件-新建-项目”,显示了如下图的“新建项目”对话框。
在该对话框中,笔者进行以下四步操作。
1. 在“已安装的模板”树[袁永福版权所有]状列表中选中“Windows”节点。
2. 在右边的列表中选中“Windows 窗体应用程序”项目。
3. 在“名称”文本框中输入“第一个Windows应用程序”。
4. 在“位置”文本框中输入保存程序文件的目录路径。
笔者点击“确定”按钮关闭对话框,则VS.NET会自动生成一个Windows应用程序的框架。此时VS.NET开发环境界面如下
学过VB的可以发现,这个用户界面和VB的用户界面很相似。对于会VB的初学者来说,使用C#开发Windows应用程序和VB差不多,只是后台编程语言由VB改成C#。
在这个VS.NET的用户界面中,主要的用户界面元素有最左边是控件工具箱,中间是窗体设计器,右上方为工程资源树状列表,右下方为控件属性编辑列表。
WinForm控件工具箱
该界面最左边为Windows控件工具箱,上面列出了所有的可以使用的控件。用户按下该列表中的某个控件图标,然后鼠标拖拽到左边的窗体上即可在窗体上新建一个指定类型的控件。比如如下图所示,用户按下“Button”项目然后拖拽到窗体上,则会在窗体上新增了一个按钮控件,控件的位置就是鼠标光标所在位置,控件大小采用默认大小。
另外当工具箱中的控件项目按下后,将鼠标移动到窗体设计器中。此时鼠标光标就变成附加控件图[袁永福版权所有]标的十字形。比如用户按下“Button”项目,然后鼠标移动到窗体设计器中,则鼠标光标样式为“
”。此时开发人员在窗体设计器中使用鼠标拖拽操作在窗体上画上一个指定位置指定大小的控件。
![](http://img.e-com-net.com/image/info8/1c8a5af7c2894f91b566c4b7cec56a40.jpg)
在默认情况下,控件工具箱中列出的控件是够用的。但这里并没有列出微软.NET框架自带的所有的Windows控件,而且也不包含第三方的控件,为了使用没有默认列出的控件,笔者需要往控件工具箱上添加新的控件。
如下图所示,笔者鼠标右击工具箱,在弹出的快捷菜单中点击“选择项”菜单项目。
该对话框中最重要的是“.NET Framework组件”分页标签页面。该页面列出了本系统安装的基于.NET平台的组件。
在.NET组件页面[袁永福版权所有]中列出了目前VS.NET所能识别的所有的Windows控件,人们可以在某个控件前面设置打勾使得该控件能显示在工具箱的控件列表中,不打勾就不显示。
对于从第三方获得的已经开发好的控件,开发者可以点击“浏览”按钮来选择包含控件的.NET程序集文件,比如“MyControls.DLL”。然后控件列表中出现了开发人员选择的.NET程序集中所包含的控件项目,开发人员就可以在这些控件前面打勾使其显示在工具项目中的控件列表中。
WinForm窗体设计器
窗体设计器具有以下几个主要功能
1. 开发人员可以从左边的控件工具箱中拖拽图标到窗体上来在窗体中放置各种各样的控件,控件的位置就是鼠标拖拽到的位置,控件的大小为默认大小;开发人员也可以按下控件工具箱中的控件图标,然后在窗体中拖拽画出指定位置指定大小的控件。
2. 开发人员可以很方便的使用鼠标拖拽操作来移动控件在窗体中的位置或者修改控件的大小。当窗体中存在可容纳子控件的容器控件时,开发人员拖拽时可以修改控件的父子关系。
3. 开发人员可以点击选中某个控件,然后在右边的属性列表中查看和修改控件的属性。
4. 开发人员可以双击控件,而且控件具有默认事件,则用户界面会切换到C#代码编辑界面,并自动构造出响应控件默认事件的C#代码结构。开发人员可以直接输入响应控件事件的程序代码了。
可以看到窗体在设[袁永福版权所有]计时的显示效果就基本上等于运行时的显示效果。实现了一种“所见即所得”的可视化界面设计功能。
可视化软件开发
微软的集成开发环境“Microsoft Visual Studio”中的Visual就是“可视化”的意思。微软最早是在Visual Basic中实现了可视化的用户界面设计功能,这引起了软件开发方法的革命。
比如对于上图的那个对话框,在没有可视化程序开发时,开发人员需要手动的编写以下的代码来构造出本窗体的用户界面。
private System.ComponentModel.IContainer components = null ;
private System.Windows.Forms.TextBox txtNumber1;
private System.Windows.Forms.ComboBox cboOperator;
private System.Windows.Forms.TextBox txtNumber2;
private System.Windows.Forms.Button btnCalculate;
private System.Windows.Forms.TextBox txtResult;
protected override void Dispose( bool disposing)
{
if (disposing && (components != null ))
{
components.Dispose();
}
base .Dispose(disposing);
}
private void InitializeComponent()
{
this .txtNumber1 = new System.Windows.Forms.TextBox();
this .cboOperator = new System.Windows.Forms.ComboBox();
this .txtNumber2 = new System.Windows.Forms.TextBox();
this .btnCalculate = new System.Windows.Forms.Button();
this .txtResult = new System.Windows.Forms.TextBox();
this .SuspendLayout();
//
// txtNumber1
//
this .txtNumber1.Location = new System.Drawing.Point( 12 , 40 );
this .txtNumber1.Name = " txtNumber1 " ;
this .txtNumber1.Size = new System.Drawing.Size( 84 , 21 );
this .txtNumber1.TabIndex = 0 ;
//
// cboOperator
//
this .cboOperator.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList;
this .cboOperator.FormattingEnabled = true ;
this .cboOperator.Items.AddRange( new object [] {
" + " ,
" - " ,
" * " ,
" / " });
this .cboOperator.Location = new System.Drawing.Point( 96 , 40 );
this .cboOperator.Name = " cboOperator " ;
this .cboOperator.Size = new System.Drawing.Size( 44 , 20 );
this .cboOperator.TabIndex = 1 ;
//
// txtNumber2
//
this .txtNumber2.Location = new System.Drawing.Point( 140 , 40 );
this .txtNumber2.Name = " txtNumber2 " ;
this .txtNumber2.Size = new System.Drawing.Size( 76 , 21 );
this .txtNumber2.TabIndex = 0 ;
//
// btnCalculate
//
this .btnCalculate.Location = new System.Drawing.Point( 216 , 39 );
this .btnCalculate.Name = " btnCalculate " ;
this .btnCalculate.Size = new System.Drawing.Size( 32 , 23 );
this .btnCalculate.TabIndex = 2 ;
this .btnCalculate.Text = " = " ;
this .btnCalculate.UseVisualStyleBackColor = true ;
//
// txtResult
//
this .txtResult.Location = new System.Drawing.Point( 248 , 40 );
this .txtResult.Name = " txtResult " ;
this .txtResult.ReadOnly = true ;
this .txtResult.Size = new System.Drawing.Size( 87 , 21 );
this .txtResult.TabIndex = 0 ;
//
// frmMain
//
this .AutoScaleDimensions = new System.Drawing.SizeF(6F, 12F);
this .AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this .ClientSize = new System.Drawing.Size( 356 , 122 );
this .Controls.Add( this .btnCalculate);
this .Controls.Add( this .cboOperator);
this .Controls.Add( this .txtResult);
this .Controls.Add( this .txtNumber2);
this .Controls.Add( this .txtNumber1);
this .FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedDialog;
this .MaximizeBox = false ;
this .MinimizeBox = false ;
this .Name = " frmMain " ;
this .Text = " 计算器 " ;
this .ResumeLayout( false );
this .PerformLayout();
}
private System.Windows.Forms.TextBox txtNumber1;
private System.Windows.Forms.ComboBox cboOperator;
private System.Windows.Forms.TextBox txtNumber2;
private System.Windows.Forms.Button btnCalculate;
private System.Windows.Forms.TextBox txtResult;
protected override void Dispose( bool disposing)
{
if (disposing && (components != null ))
{
components.Dispose();
}
base .Dispose(disposing);
}
private void InitializeComponent()
{
this .txtNumber1 = new System.Windows.Forms.TextBox();
this .cboOperator = new System.Windows.Forms.ComboBox();
this .txtNumber2 = new System.Windows.Forms.TextBox();
this .btnCalculate = new System.Windows.Forms.Button();
this .txtResult = new System.Windows.Forms.TextBox();
this .SuspendLayout();
//
// txtNumber1
//
this .txtNumber1.Location = new System.Drawing.Point( 12 , 40 );
this .txtNumber1.Name = " txtNumber1 " ;
this .txtNumber1.Size = new System.Drawing.Size( 84 , 21 );
this .txtNumber1.TabIndex = 0 ;
//
// cboOperator
//
this .cboOperator.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList;
this .cboOperator.FormattingEnabled = true ;
this .cboOperator.Items.AddRange( new object [] {
" + " ,
" - " ,
" * " ,
" / " });
this .cboOperator.Location = new System.Drawing.Point( 96 , 40 );
this .cboOperator.Name = " cboOperator " ;
this .cboOperator.Size = new System.Drawing.Size( 44 , 20 );
this .cboOperator.TabIndex = 1 ;
//
// txtNumber2
//
this .txtNumber2.Location = new System.Drawing.Point( 140 , 40 );
this .txtNumber2.Name = " txtNumber2 " ;
this .txtNumber2.Size = new System.Drawing.Size( 76 , 21 );
this .txtNumber2.TabIndex = 0 ;
//
// btnCalculate
//
this .btnCalculate.Location = new System.Drawing.Point( 216 , 39 );
this .btnCalculate.Name = " btnCalculate " ;
this .btnCalculate.Size = new System.Drawing.Size( 32 , 23 );
this .btnCalculate.TabIndex = 2 ;
this .btnCalculate.Text = " = " ;
this .btnCalculate.UseVisualStyleBackColor = true ;
//
// txtResult
//
this .txtResult.Location = new System.Drawing.Point( 248 , 40 );
this .txtResult.Name = " txtResult " ;
this .txtResult.ReadOnly = true ;
this .txtResult.Size = new System.Drawing.Size( 87 , 21 );
this .txtResult.TabIndex = 0 ;
//
// frmMain
//
this .AutoScaleDimensions = new System.Drawing.SizeF(6F, 12F);
this .AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this .ClientSize = new System.Drawing.Size( 356 , 122 );
this .Controls.Add( this .btnCalculate);
this .Controls.Add( this .cboOperator);
this .Controls.Add( this .txtResult);
this .Controls.Add( this .txtNumber2);
this .Controls.Add( this .txtNumber1);
this .FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedDialog;
this .MaximizeBox = false ;
this .MinimizeBox = false ;
this .Name = " frmMain " ;
this .Text = " 计算器 " ;
this .ResumeLayout( false );
this .PerformLayout();
}
编写这样的代码是枯燥范围而且效率低下的过程。开发人员在编写代码的过程中需要在脑海中想象出这段代码运行后的窗体界面。需要多次运行程序显示窗体查看运行效果后修改代码进行控件位置大小的微调。当窗体界面中需要新增或删除控件时会影响其他控件的排版,此时又得多次运行程序显示窗体来修改代码进行微调。
当窗体界面很复杂,开发人员需要编写和维护几千行的构造窗体用户界面的代码,这一大段代码开发和维护成本是非常高的。
而是用可视化的窗[袁永福版权所有]体用户界面设计功能能大大降低设计和维护窗体用户界面的成本。在窗体设计器中,开发人员即可看到控件在窗体中的排版效果,并能比较精确的进行控件排版微调,还可以使用控件的属性编辑器来编辑控件属性,并能实时的看到用户界面的修改效果。这样能很大的提高用户界面设计工作效率,缩短开发和维护时间。
另外从开发方式来说,可视化用户界面设计降低了劳动强度。在没有可视化设计前,开发人员完全靠写代码来拼凑软件用户界面,写代码是一种高强度的劳动,开发人员需要端坐在电脑前,脑子里想出代码,然后双手在键盘上快速的输入代码,此时无论身体还是精神处于一定的紧张状态,劳动强度高,比较容易疲劳。
而可视化用户界面设计过程中,大部分操作是靠鼠标操作的,单手即可完成,因此开发人员不需要端坐,而可以采用比较休闲舒适的坐姿,而且设计过程比较简单,大脑思考不多,此时身体和精神处于较为放松的状态,劳动强度低,不容易疲劳。
有人认为可视化设计降低了对软件开发人员的要求,对于其成长不利。个人觉得并不是这样的。
可视化操作掩盖了软件用户界面的后台实现,由于人们普遍具有惰性,能使用可视化操作完成用户界面的设计任务后就不深究其后台的实现,这确实不利于开发人员的技术钻研。不过学海无涯,软件开发涉及到很多很多技术的细节,若开发人员要了解软件开发过程中所有的技术细节,尤其是构造用户界面的比较枯燥乏味的技术细节,这会耗掉相当多的精力,从而减少了对其他技术细节的关注度。
现代软件的开发内容分为技术内容和业务内容。对于行业应用软件,开发人员应当将主要精力放置在行业业务细节,需要花大精力来理解客户业务需求,包括客户的业务数据和执行流程。只有深入理解了业务,开发人员才能利用软件开发技术来开发符合业务内容的应用软件。因此开发人员应当花费主要精力在深入理解客户业务上,充分掌握客户的业务细节。
由于人的精力是有限的,因此开发人员应当尽量少的降低对技术细节的精力消耗量,这就是各种应用系统框架出现的原始需求。可视化程序设计就能隐藏大量的技术细节,使得开发人员能快速高效的设计程序,降低花在软件开发技术细节上的精力消耗。这优化了开发人员的精力配置,使得开发人员不必纠缠在软件技术细节问题上,更注重于业务的理解和实现,提高软件开发的生产效率。
而且可视化软件设计能降低对开发人员的水平要求,由于可视化软件开发操作简单,不需要写代码,这能降低软件开发人员的水平要求,使得大量的低级软件开发人员也能参与商业软件的开发。
一般来说,一个企业的软件开发人员是高水平的开发人员少,低水平的开发人员多。高水平的开发人员能开发和维护上万行的源代码,而低水平的开发人员只能维护几千行的源代码,而高校实习生们只能编写几百行的源代码。因此不能指望低水平的开发人员能通过编写程[袁永福版权所有]序代码来构造软件的用户界面。
若没有可视化软件开发,则企业中必然存在大量的不能投入实际工作的开发人员,这对企业来说会有巨大的不必要的成本浪费。而可视化软件开发掩盖了一些技术细节,使得低水平的开发人员能比较独立的进行软件的用户界面开发,这样企业中所有的开发人员都能投入实际工作,不会浪费人力资源,提高企业的盈利水平。
当然,完全的使用可视化的软件设计确实纵容了开发人员的惰性,大量的没有钻研精神的软件开发人员只利用了可视化软件设计的功能而不去思考其掩盖的技术细节,这不利于由低水平的软件开发人员升级为高水平的软件开发人员。笔者见过这类的开发人员,使用VS.NET从事开发工作若干年,只会拖拽生成DataSet,然后在窗体上放置若干个控件,直接绑定到数据源上,几年下来都是干这样的工作。对此少数开发人员觉得工作一段时期自己的水平没有多大提高而有所焦虑并试图改变;当然也有很多懒惰的开发人员对此麻木不仁,技术水平原地踏步,终难成大器。
因此有梦想的开发人员还需要大力发扬钻研精神,不拘泥于可视化软件设计带来的便利,还需要深入理解相关技术细节,也是初级开发人员成长的必由之路。
有完美主义者认为[袁永福版权所有]让初学者学习软件开发,必须抛弃可视化软件设计,一切用手工编写代码来实现功能,这样做为得是让学习者一开始就学习技术底层细节。笔者个人觉得不妥:
从软件开发学习者的角度来说,一开始就学习技术底层细节就像让小学生学习高难度的奥数一样,对于少数天才这是提升能力的较好方式,但对于大多数普通人来说那是拔苗助长。过高的难道将较大的打击学习者的信心,使得学习者丧失对软件开发的兴趣,容易导致其放弃学习。
持精英教育观点的人士或者会说就是这样才能大浪淘沙,能发现并培养出高水平的软件开发人员。可是中国软件行业需要几十万上百万的软件开发人员,若通过这种方式培养不知何年那月才能凑齐这个数字。
从企业的角度来说,一开始就让初学者或者大学毕业生学习技术底层细节,则时间比较长,可能需要好几个月甚至一年以上的时间,还得让老员工花时间悉心指导才可能成功;若经过培训发现初学者不是软件开发的料则之前的工作全部浪费。这种培养方式对自负盈亏的企业来说成本太高了,得不偿失。
若让初学者首先学习可视化软件设计,则学习难度低,速度快,而且能较快的投入实际的软件开发过程中。因此能让初学者或者大学毕业生尽快的投入实际工作,为企业带来工作业绩。而且能较快的看到自己能投入实际工作,这对大学毕业生来说是一种激励,使其能较快的建立起职场自信心,形成对软件开发工作的兴趣,这对企业和个人来说都有好处。
综上可以看到,可视化软件设计确实较大的提高了开发人员的工作效率,降低软件的开发成本。[袁永福版权所有]