最经工作需要用.Net做winform程序,以前因为个人对windows的东西不太感冒,就接触很少,但是为了生活也没办法,多学习一样技术也没坏处。

  C#语法跟C++和java非常类似,从变量定义、语句、循环、名字空间、异常处理等都很相似,有一定编程基础的只需要稍微了解一下就可以上手。我刚接触C#和VS没几天,几乎没学什么语法,通过百度(google上不去啊)一边查一边做,基本上可以做出一个简单的winform小程序来。微软把几乎所有的东西都封装好了,我只需要大致了解一下windows编程的思路,通过拖动控件和添加事件处理,就能做一个最基础的小软件。

  下面就随手记录最近零星学的东西,以防以后忘记。

1、从vs上新建一个winform工程后,默认导入system、system.windows.forms、system.text等包,这叫做工程的引用,主要需要关注From1.cs, From1.Designer.cs,  Program.cs三个文件,Program.cs是程序的入口,代码如下:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Windows.Forms;

namespace WindowsFormsApplication1
{
  static class Program
  {
    [STAThread]
    static void Main()
    {
      Application.EnableVisualStyles();
      Application.SetCompatibleTextRenderingDefault(false);
      Application.Run(new Form1());
    }
  }
}

核心就是Application.Run(new Form1())这行代码,表示开启了一个winform的主事件循环,From1是主窗口,循环等待并响应外部事件。

From1.Designer.cs是定义了主窗体的一些控件属性,在程序开始就生成这些控件,vs建议不要直接编辑这里的代码,如果要添加控件或者注册事件最好是通过“设计”页面来处理。

From1.cs是需要主要编辑的文件,用于添加事件处理。

2、在windows上编写GUI程序都是基于windows的消息机制,简单来说就是操作系统为每个应用程序维护一个消息队列,操作系统接收来自鼠标、键盘传来的事件,封装成一种叫消息的数据结构,然后传给对应的应用程序窗体,通过委托调用事件方法进行处理。

在C#中,windows消息都进行了面向对象封装,叫event(事件)。在定义event的时候指定了一个委托,然后注册事件处理的时候需要调用这个委托。

         public delegate void EventHandler(object sender,EventArgs e);   定义了一个事件处理的委托
         public event EventHandler MouseClick;                                      定义一个事件

在From1.Designer.cs中需要添加下面一行:

            this.button1.MouseClick+= new System.EventHandler(this.button1_Click); 

表示为按钮button1添加一个MouseClick事件,对应的事件处理函数时this.button1_Click,我们需要再Form1.cs中实现这个处理方法.

当然,如果只是简单应用,我们不需要自己定义event,.Net已经为我们定义绝大部分可能遇到的事件,我们要做的就是注册事件、处理事件。

3、GUI编程一个重点就是对异步和线程的使用,Application.Run(new Form1())表示开始一个主线程,启动Form1为主窗口,它不断循环等待事件的发生。当发生一个鼠标Click事件,一种方式使用同步调用,我们暂停主线程等待鼠标Click事件处理完毕然后继续运行,这样整个主窗体会处于“假死”状态,如果事件处理需要花很长时间,程序将完全卡死不能动。我前几天实现的winform程序是后台调用一个外部程序,要执行很长时间,解决的方法就是另外开启一个线程:

首先引用名字空间

using System.Threading;       导入线程相关的类

然后在事件函数中添加一个线程

Thread ts = new Thread(new ParameterizedThreadStart(work));
ts.Start(this);

或者

Thread ts = new Thread(new ThreadStart(work));

ts.Start();

两种添加线程方法的区别就是,第一个可以传入一个object参数,一般都是传进主窗体的this,这样方便我们在线程中操作主窗体的属性。

work方法中就是线程的代码,我需要在事件运行的时候,不断获取外部程序的标准输出和标准错误输出,所以可以线程中进行处理

4、调用外部程序使用Process类,在线程中可以用waitforexit方法等待进程执行完毕而不用担心会阻塞主线程。

Process调外部程序需要注意几点:

(1)在WaitForExit后使用Process.ExitCode 获取返回值,以此来判断外部程序是否执行成功

(2)外部程序可能出异常一直没有返回值,需要使用WaitForExit的一个重载设置最长等待时间

(3)子进程执行完毕后,使用Dispose和Close释放相关资源并关闭;子进程执行异常后,通过Kill杀死