亮剑C#项目开发案例导航
上QQ阅读APP看本书,新人免费读10天
设备和账号都新为新人

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控件,功能性和易用性都有了明显的提升。