1.2 Windows Forms开发技术
.NET Framework的Windows Forms开发技术提供了开发Windows窗体用户界面的能力,Windows Forms是.NET Framework提供的技术之一,它使得开发人员可以充分地利用客户端的资源,来使用Microsoft Windows操作系统中丰富的用户界面特性。
1.2.1 创建Windows Forms应用程序
如果读者是熟悉其他Windows平台软件开发的开发人员,那么对于Windows Forms一定不会陌生。Windows Forms提供了与其他Windows开发工具(比如Delphi等)相同的开发Windows应用程序的能力,如下所示。
● 可视化窗体继承特性:可以定义一个窗口模板,提供一些必备的功能。例如,创建一个具有工具栏、菜单栏及模板代码的用户界面,子窗体通过继承基窗体的特性,大大提高了开发人员的生产力,促进了代码的重用。
● 功能强大的数据绑定功能:.NET Framework 1.1提供了较弱的数据绑定特性,开发人员不得不创建大量的代码来进行数据绑定,而且极不灵活。从.NET Framework 2.0到现在的.NET Framework 4.0,数据绑定功能得到了极大的完善。通过使用BindingSource控件和增强的强类型数据集,开发人员可以可视化的方式开发Windows Forms应用程序。
Windows Forms的优越性还有很多,比如精确定位的能力、强大的图形处理功能等,下面新建一个简单的Windows Forms应用程序,来了解一下其结构,步骤如下:
(1) 打开VS 2010,选择主菜单中的“文件”|“新建”命令,在弹出的“新建项目”窗口中选择“Windows窗体应用程序”模板,如图1.21所示。
图1.21 新建Windows窗体应用程序
为应用程序指定名称为SimpleFormDemo,单击“确定”按钮,VS 2010将会自动创建一个名为Form1.cs的主窗体文件和一个Program.cs的应用程序入口点文件。Program.cs中定义了一个静态的Program类,该类中定义了一个静态的Main()方法,应用程序在启动时将执行该方法,该方法的代码如下所示。
代码位置:见光盘中本章源代码的Program.cs类。
01 static class Program 02 { 03 /// <summary> 04 /// 应用程序的主入口点。 05 /// </summary> 06 [STAThread] 07 static void Main() 08 { 09 Application.EnableVisualStyles(); //启用视觉样式支持 10 Application.SetCompatibleTextRenderingDefault(false); 11 Application.Run(new Form1()); //启动Form1作为应用程序的主窗口 12 } 13 }
● 第09行代码调用Application类的EnableVisualStyles()方法,指示如果控件和操作系统支持视觉样式,则控件将以视觉样式进行绘制。
● 第10行代码调用SetCompatibleTextRenderingDefault指定使用兼容的文本输出。
● 第11行代码的Run方法是一个非常重要的方法,它将处理Windows消息,接收各种事件。为其传入的窗体实例表示这是一个应用程序的主窗体。
在Windows Forms中,每个应用程序都要有一个Application,且只能有一个Application对象实例,示例代码中使用了Application类的静态方法设置了应用程序级别的属性。在示例代码中将Form1对象实例作为Run方法的参数,那么Form1将作为应用程序的主窗体。当Form关闭时,整个应用程序将退出。
(2) 在VS 2010的文档视图中选中Form1,在属性窗口中设置Text属性为记事本,指定Name属性为FrmMain,从工具箱中拖一个MenuStrip控件到桌面上,添加图1.22所示的菜单栏,然后拖放一个RichTextBox控件,设置其Dock属性为Fill。最后添加一个StatusStrip控件到窗体上,显示为一个状态条。
图1.22 记事本示例界面
(3) 实现了用户界面与菜单后,接下来为菜单进行编码。当用户选择“新建”菜单项时,将执行如下的代码来新建一个文本文件。
代码位置:见光盘中本章源代码的Form1.cs类。
01 private void 新建ToolStripMenuItem_Click(object sender, EventArgs e) 02 { 03 if (richTextBox1.Modified) 04 { //判断用户是否更改了文本 05 if (MessageBox.Show("当前文本已经改变,是否要进行保存?", "保存确认", 06 MessageBoxButtons.YesNo) == DialogResult.OK) 07 { 08 string filename = this.Text; //文件名 09 if (filename == "未命名") //如果文件未命名 10 { 11 SaveFileAs(); //调用另存为的功能 12 richTextBox1.Clear(); //清空 13 this.Text = "未命名"; //指定文件名 14 toolStripStatusLabel1.Text = "当前文档:" + this.Text; 15 } 16 else 17 { 18 SaveFile(filename); //调用保存文件方法 19 richTextBox1.Clear(); //清空 20 this.Text = "未命名"; //指定名称 21 toolStripStatusLabel1.Text = "当前文档:" + this.Text; 22 } 23 } 24 else 25 { 26 richTextBox1.Clear(); //直接清空 27 this.Text = "未命名"; //指定名称 28 toolStripStatusLabel1.Text = "当前文档:" + this.Text; 29 } 30 } 31 this.Text = "未命名"; //如果没有修改,指定未命名 32 } 33 private void SaveFile(string fileName) 34 { 35 richTextBox1.SaveFile //调用RichTextBox的SaveFile方法 36 (fileName, RichTextBoxStreamType.PlainText); 37 } 38 private int SaveFileAs() 39 { //SaveFileAs将弹出一个保存文件窗口 40 SaveFileDialog objSaveFile=new SaveFileDialog(); 41 int result=0; 42 objSaveFile.DefaultExt = "*.txt"; //指定扩展名 43 objSaveFile.RestoreDirectory = true; 44 objSaveFile.Filter = "文本文件(*.txt)|*.txt";//过滤器 45 if(objSaveFile.ShowDialog() //判断用户是否单击了OK 46 DialogResult.OK &&objSaveFile.FileName!=string.Empty) 47 { 48 richTextBox1.SaveFile //调用SaveFile方法保存为纯文本 49 (objSaveFile.FileName, RichTextBoxStreamType.PlainText); 50 result = 1; 51 } 52 return result; //返回保存结果 53 }
● 第03行代码判断用户是否在RichTextBox控件中修改了内容,如果修改了,在选择“新建”菜单项时,将弹出当前文本已经改变的窗口,提示用户进行保存。
● 第05~22行在用户确定保存后,根据当前文件的命名,调用SaveFile()自定义方法保存到指定文件名中。如果是未命名,则调用SaveFileAs()方法对文件进行另存。
● 第24~29行代码在用户取消保存时,直接清空文本框,进行新建初始化工作。
● 第33~37行代码调用了RichTextBox控件的SaveFile()方法,将文本信息保存为纯文本。
● 第38~52行的SaveFileAs()方法将首先弹出一个“保存文件”窗口,然后初始化“保存文件”窗口,根据用户选择文件名调用SaveFile()方法保存文件。
(4) 如果用户选择“打开”菜单项,将弹出一个“打开文件”窗口,要求用户选择要打开的文本文件,用户选择后将在RichTextBox控件中打开文本文件,代码如下所示。
代码位置:见光盘中本章源代码的Form1.cs类。
01 private void 打开ToolStripMenuItem_Click(object sender, EventArgs e) 02 { 03 string fileName; //文件名称 04 string filetempPath; 05 filetempPath = OpenFile(); //调用OpenFile方法打开文件 06 filePath = Path.GetDirectoryName(filetempPath); //获取路径 07 fileName = Path.GetFileName(filetempPath) ; //获取文件名 08 this.Text = fileName; //显示文件名 09 toolStripStatusLabel1.Text = //在状态栏中显示 10 toolStripStatusLabel1.Text = "当前文档:" + this.Text; 11 } 12 private string OpenFile() 13 { //OpenFile方法用于显示打开窗口,并读取文件 14 OpenFileDialog objOpenFile = new OpenFileDialog(); 15 string filePath=string.Empty; //获取文件路径 16 objOpenFile.Filter = "文本文件(*.txt)|*.txt"; 17 objOpenFile.DefaultExt = "*.txt"; 18 if (objOpenFile.ShowDialog() == //打开文件窗口 19 DialogResult.OK && objOpenFile.FileName != string.Empty) 20 { 21 richTextBox1.LoadFile //加载文件 22 (objOpenFile.FileName, RichTextBoxStreamType.PlainText); 23 filePath = objOpenFile.FileName; //获取文件路径和文件名 24 } 25 return filePath; //返回文件路径和文件名 26 }
● 第03~04行代码定义了两个临时的变量,用来保存文件名和临时的文件路径信息。
● 第05~09行代码调用OpenFile()方法打开文件,返回打开的文件名,第06行代码将文件路径保存到类私有变量中。第07行代码获取文件名,第08~09行代码则在标题栏和状态栏显示文件信息。
● 第12~25行代码的OpenFile()方法首先打开一个“打开文件”窗口,要求用户选择一个文本文件,然后RichTextBox控件将用户选择的文本加载到文本框中。
(5) “保存”和“另存为”菜单项调用了SaveFile()和SaveFileAs()两个方法,代码如下所示。
代码位置:见光盘中本章源代码的Form1.cs类。
01 private void 保存ToolStripMenuItem_Click(object sender, EventArgs e) 02 { 03 string fileName; //保存文件名的变量 04 int done; 05 if (this.Text == "未命名") 06 { 07 done = SaveFileAs(); //如果未命名文件,则调用SaveFileAs()方法 08 if (done == 1) 09 { 10 MessageBox.Show("文件已经成功保存"); //如果保存成功,则显示成功消息 11 } 12 } 13 else 14 { 15 fileName = filePath + @"\" + this.Text; //获取文件名 16 SaveFile(fileName); //保存文件 17 } 18 } 19 private void 另存为ToolStripMenuItem_Click(object sender, EventArgs e) 20 { 21 SaveFileAs(); //调用SaveFileAs()方法保存文件 22 }
● 第03~12行代码判断是否是一个命名的文本文件,如果未命名,则调用SaveFileAs()方法。
● 第13~17行代码在文件为命名文件时,调用SaveFile()方法保存文件。
● 第19~22行的“另存为”菜单项的代码直接调用SaveFileAs()方法进行“另存为”操作。
至此,实现了一个简单的记事本,它具有打开、保存、新建等功能。在该示例中演示了如何创建一个简单的Windows Forms应用程序,介绍了如何使用控件、响应控件的事件等操作。
1.2.2 使用Windows Forms开发数据库应用程序
.NET Framework 2.0之后的版本对于Windows Forms开发数据绑定进行了增强,改进了对数据绑定的支持,提供了强大的BindingSoruce控件,增强的强类型功能及局布类的出现,使得在强类型中编写自定义逻辑不用担心有被覆盖的危险。本节以一个简单的实例,演示了如何以尽量少的代码或者是不需要代码,创建一个具有增、删、改功能的应用程序,创建步骤如下。
(1)新建一个DataAppDemo的Windows窗体应用程序,设置其Title为“AdventureWorks联系人”,设置其Name属性为FrmMain。
(2)选择VS 2010主菜单的“数据”|“显示数据源”命令,将显示一个数据源窗口。单击“添加数据源”链接,即弹出一个向导窗口,在向导窗口的数据源类型中选择“数据库”选项,单击“下一步”按钮,再在选择数据源窗口中创建一个连接到AdvantureWorks数据库的数据连接。单击“下一步”按钮将连接保存到配置文件中,再次单击“下一步”按钮,在“选择数据库对象”页面中选择Contact数据表,如图1.23所示。在“DataSet名称”文本框中指定数据集的名称为“AdventureWorksDataSet”,单击“完成”按钮完成数据源的添加。
(3)在数据源窗口中,选中AdventureWorksDataSet数据集的Contact表,将它拖到文档窗口的主窗体上。VS 2010将会自动添加一个DataGridView控件、一个BindingNavigator控件,以及AdventureWorksDataSet、BindingSource和TableAdapter控件。
(4)在数据源窗口中选中Contact表,单击下拉箭头选择“详细信息”选项,然后再将Contact拖动到窗体上,VS 2010会为控件产生详细信息控件。经过简单的编排后,就可以按下F5键运行程序。可以看到一个简单的具有增、删、改功能的窗体已经做完了,用户可以编辑联系人、删除联系人或添加新的联系人,用户界面如图1.24所示。
图1.23 选择Contact数据表
图1.24 联系人编辑窗口
当在DataGridView控件中单击不同的记录行时,详细信息文本框控件会自动进行同步,用户可以直接在文本框中更改信息。单击“保存”按钮后,将会保存信息,也可以单击“新增”按钮,新增一条记录,然后单击“保存”按钮,保存联系人信息。VS 2010自动添加了在窗体加载时填充数据集的代码,以及保存到数据库中的代码,如下所示。
代码位置:见光盘中本章源代码的Form1.cs类。
01 private void contactBindingNavigatorSaveItem_Click(object sender, EventArgse) 02 { 03 this.Validate(); //进行验证工作 04 this.contactBindingSource.EndEdit(); //提交验证更改 05 this.tableAdapterManager. //用TableAdapterManager的UpdateAll方法更新记录 06 UpdateAll(this.adventureWorksDataSet); 07 } 08 private void FrmMain_Load(object sender, EventArgs e) 09 { 10 this.contactTableAdapter.Fill //填充记录 11 (this.adventureWorksDataSet.Contact); 12 }
● 第03行代码调用窗体Validate()方法进行验证工作。
● 第04行代码将用户在窗体上所做的更改提交给BindingSource。
● 第05~06行代码调用了TableAdapterManager的UpdateAll()方法,向数据库提交对数据集的更改。
● 第08~12行代码的Load事件处理代码调用了contactTableAdapter的Fill()方法填充了数据表,这样用户界面有数据得以显示。
Windows Froms改进型的DataGridView控件提供了大量的定制特性,相较于其前一个版本的DataGrid控件,功能性和易用性都有了明显的提升。