在平常寫WinForm程序時,都是使用Visual Studio 的向導功能,選中項目類型為Windows Form Application,IDE就會為我們生成好代碼框架。這無疑使非常方便的,但是卻不利於我這樣的新手了解程序的運行機理。
下面我試着,拋棄IDE生成的代碼框架,從一個空的項目來創建一個Windows From的應用程序。
一 . 創建窗體
創建完Empty Project后,第一步就需要添加一些必要的引用:System , System.Drawing , System.Windows.Forms。然后向項目中添加一個名為HelloWorld的類 。
1: using System.Windows.Forms;
2:
3: namespace test
4: {
5: class HelloWord
6: {
7: public static void Main()
8: {
9: Form frm = new Form();
10: frm.Show();
11: }
12: }
13: }
上面的代碼中,在Main()方法中,通過實例化Form類來創建一個窗體,然后調用show()方法讓其顯示。在運行該程序前,需要先更改項目的輸出類型為Windows Application。運行程序,一個窗口閃爍下就消失了。這是由於一個Windows應用程序結束時會銷毀其所創建的所有窗口。我們知道,Windows應用程序時事件驅動,在沒有觸發關閉事件,應用程序是不應該被關閉的。顯然的,上面的示例程序並沒有進入到一個消息循環中,就已經結束了。
怎樣讓程序進入到消息循環?這時就需要一個神奇的方法”Run”了,它能讓應用程序進入到消息循環中,接受輸入事件。
改造上面的代碼如下:
using System.Windows.Forms; namespace test { class HelloWord { public static void Main() { Form frm = new Form(); frm.Show(); Application.Run(); } } }
運行程序,得到一個標准的窗口,能移動、最大化、最小化,但是在關閉窗口時卻出現了問題,只是窗口消失了但是進程卻並沒有結束(在調試下運行會很容易的發現這點)。這是因為,關閉了窗口只是銷毀了窗口,並不是結束程序。要想關閉窗口同時程序結束,將一個Form的實例作為參數傳遞給Run是一個很好的選擇。
1: using System.Windows.Forms;
2:
3: namespace test
4: {
5: class HelloWord
6: {
7: public static void Main()
8: {
9: Form frm = new Form();
10: Application.Run(frm);
11: }
12: }
13: }
上面代碼並沒有調用show方法,這是因為當一個窗體作為參數時,Run會將該窗體設置為可見,並讓該窗體進入到消息循環。當關閉窗體時,Run方法會返回到Main函數中,接着執行完Application.Run()后面的代碼后,程序結束。
二.處理事件
Windows 應用程序是事件驅動的,上面已經創建好了窗體,下面來響應窗體的輸入事件。
窗體一個比較重要的事件就是Paint事件,它在窗體被創建、窗體的 客戶區失效或部分失效時會被觸發。對該時間的處理是通過一個委托實現的。
public delegate void PaintEventHandler(object sender, PaintEventArgs e);
對Paint事件的處理,只需要定義一個和上面委托有相同的簽名的靜態的方法作為事件的處理程序,然后將該方法和Paint事件綁定即可。
1: using System.Windows.Forms;
2: using System.Drawing;
3:
4: namespace test
5: {
6: class HelloWord
7: {
8: public static void Main()
9: {
10: Form frm = new Form();
11: frm.Paint += new PaintEventHandler(frm_Paint); //注冊事件處理程序
12: Application.Run(frm);
13: }
14:
15: //事件處理程序
16: static void frm_Paint(object sender, PaintEventArgs e)
17: {
18: Form frm = (Form)sender;
19: Graphics g = e.Graphics;
20: g.Clear(Color.Black);
21: g.DrawString("Hello Word", frm.Font, Brushes.White, new Point(20, 20));
22: }
23: }
24: }
和Paint事件類似,也可以處理窗體的鼠標點擊事件
1: using System;
2: using System.Windows.Forms;
3: using System.Drawing;
4:
5: namespace test
6: {
7: class HelloWord
8: {
9: public static void Main()
10: {
11: Form frm = new Form();
12: frm.Paint += new PaintEventHandler(frm_Paint); //注冊Paint事件處理程序
13: frm.Click += new System.EventHandler(frm_Click);//注冊Click事件處理程序
14: Application.Run(frm);
15: }
16:
17: // Click事件處理程序
18: static void frm_Click(object sender, EventArgs e)
19: {
20: Form frm = (Form)sender;
21: //在標題欄顯示鼠標單擊的位置
22: frm.Text = Cursor.Position.X.ToString() + ":" + Cursor.Position.Y.ToString();
23: }
24:
25: //事件處理程序
26: static void frm_Paint(object sender, PaintEventArgs e)
27: {
28: Form frm = (Form)sender;
29: Graphics g = e.Graphics;
30: g.Clear(Color.Black);
31: g.DrawString("Hello Word", frm.Font, Brushes.White, new Point(20, 20));
32: }
33: }
34: }
三.繼承窗體
上面的代碼看上去已經實現了一個窗體,能為窗體賦於某些屬性,響應一些事件的輸入,實際則不然。因為我們只是通過創建Form類的一個實例來實現了一個窗體,這是不夠,Form的某些功能是用protected保護的,以此要想實現窗體的全部功能就需要“變成”窗體,繼承Form創建一個新的類則是一個很好的選擇。
1: using System;
2: using System.Drawing;
3: using System.Windows.Forms;
4:
5: namespace test
6: {
7: class InheritClass:Form
8: {
9: public static void Main()
10: {
11: Application.Run(new InheritClass());
12: }
13:
14: public InheritClass()
15: {
16: Text = "通過繼承創建窗體";
17: BackColor = Color.Black;
18: }
19: }
上面代碼InheritClass繼承自Form,然后實例化InheritClass來創建窗體。這也是使用Windows Form類庫在C#中創建一個窗體的正式的方法。
通過繼承來實現的窗體的好處之一就是能夠訪問Form中受保護的成員,例如可以重寫(override)OnPaint方法,這樣就不必處理Paint事件了。
1: using System;
2: using System.Drawing;
3: using System.Windows.Forms;
4:
5: namespace test
6: {
7: class InheritClass:Form
8: {
9: public static void Main()
10: {
11: Application.Run(new InheritClass());
12: }
13:
14: public InheritClass()
15: {
16: Text = "通過繼承創建窗體";
17: BackColor = Color.Black;
18: }
19:
20: protected override void OnPaint(PaintEventArgs e)
21: {
22: //base.OnPaint(e);
23: Graphics g = e.Graphics;
24: g.DrawString("Hello World", Font, Brushes.Yellow, new Point(0, 0));
25: }
26: }
27: }
四.最后
上面的代碼雖然也能工作,但是看起來總有些不夠整潔,特別是Main方法的位置,總是讓人有些別扭。對代碼改造下,讓其看起來整潔些。
再建立一個program類,將程序的入口Main方法放入到該類中
這是program類
1: using System;
2: using System.Windows.Forms;
3:
4: namespace test
5: {
6: class program
7: {
8: public static void Main()
9: {
10: Application.Run(new InheritClass());
11: }
12: }
13: }
InheritClass類
1: using System;
2: using System.Drawing;
3: using System.Windows.Forms;
4:
5: namespace test
6: {
7: class InheritClass:Form
8: {
9: public InheritClass()
10: {
11: Text = "通過繼承創建窗體";
12: BackColor = Color.Black;
13: }
14:
15: protected override void OnPaint(PaintEventArgs e)
16: {
17: //base.OnPaint(e);
18: Graphics g = e.Graphics;
19: g.DrawString("Hello World", Font, Brushes.Yellow, new Point(0, 0));
20: }
21: }
22: }
是不是有點像IDE自動生成的代碼了呢?