探查窗體---進階編程篇(三)


  在C#窗體應用程序開發中,窗體也是類,按照正常的先后順序來說,應該先介紹下接口和類再應該介紹窗體的,但是此處我會根據最常用和很容易忽略的地方來講解編程開發,更多的是提供一些自我思考的思路。

  我們一開始學習的時候,都是從控制台程序學習,后來就想要做界面,自然而然的就接觸到了winform程序,然后使用了非常簡單,操作流程的方式將控件拖到了窗體中,然后點擊控件,開始修改一些屬性參數,稍微多使用幾次后,就會非常的嫻熟,我剛開始接觸時也不會去深究背后的原理技術是什么。上述的一系列操作關聯了非常多的技術細節,有許多的細節都是比較高級的主題,在初學者中確實不應該提及,但此處為了講明白這些原理卻又不得不提專業名詞,我相信只要是我們真的想學習編程,就一定想知道它為什么就能實現這些功能。

  我們還是一個最簡單的winform窗體程序作為切入點,新建一個窗體程序后:

  我們拋開設計器不談(設計器中其實沒有代碼支持,只是IDE提供的一個可視化操作效果),一個窗體程序,就是一個類,只不過在兩個地方定義了,第一部分是我們在代碼開發中經常碰到的,幾乎所有的代碼都在這里開發完成。

 1 using System;
 2 using System.Collections.Generic;
 3 using System.ComponentModel;
 4 using System.Data;
 5 using System.Drawing;
 6 using System.Linq;
 7 using System.Text;
 8 using System.Threading.Tasks;
 9 using System.Windows.Forms;
10 
11 namespace WindowsFormsApp1
12 {
13     public partial class Form1 : Form
14     {
15         public Form1()
16         {
17             InitializeComponent();
18         }
19         
20     }
21 }

第二部分的代碼藏的比較深,在Form1.Designer.cs中,至於資源存儲不再本次的討論范圍內。

 

 1 namespace WindowsFormsApp1
 2 {
 3     partial class Form1
 4     {
 5         /// <summary>
 6         /// 必需的設計器變量。
 7         /// </summary>
 8         private System.ComponentModel.IContainer components = null;
 9 
10         /// <summary>
11         /// 清理所有正在使用的資源。
12         /// </summary>
13         /// <param name="disposing">如果應釋放托管資源,為 true;否則為 false。</param>
14         protected override void Dispose(bool disposing)
15         {
16             if (disposing && (components != null))
17             {
18                 components.Dispose();
19             }
20             base.Dispose(disposing);
21         }
22 
23         #region Windows 窗體設計器生成的代碼
24 
25         /// <summary>
26         /// 設計器支持所需的方法 - 不要修改
27         /// 使用代碼編輯器修改此方法的內容。
28         /// </summary>
29         private void InitializeComponent()
30         {
31             this.SuspendLayout();
32             // 
33             // Form1
34             // 
35             this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 12F);
36             this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
37             this.ClientSize = new System.Drawing.Size(528, 375);
38             this.Name = "Form1";
39             this.Text = "Form1";
40             this.ResumeLayout(false);
41 
42         }
43 
44         #endregion
45     }
46 }

 

  我們可以清楚的看到第一部分的構造方法中調用了InitializeComponent()方法,該方法的源代碼就在第二個文件中,我們來看看源代碼中都寫了什么,掛起布局,設置放大縮小維度,模式,窗口大小,窗體名稱,顯示文本,恢復布局。OK,看到這里,我相信各位看官都可以嘗試着修改修改參數,看看會不會有什么變化,比如修改下窗體名稱,大小等等。再回到設計器界面就可以看到已經修改完成了,接下來就是重頭戲了,我們嘗試着在窗體上添加一個按鈕,就是拖控件的方式,拖上去后看看代碼會不會變化:

  就是這樣的效果,先不要去追加按鈕事件,或是調整按鈕大小,我們來看看form1類的代碼會不會發生變化,我們發現Form1.cs中的代碼沒有任何改變,那么我們可以肯定另一個文件中發生了代碼變化:

 1 namespace WindowsFormsApp1
 2 {
 3     partial class Form1
 4     {
 5         /// <summary>
 6         /// 必需的設計器變量。
 7         /// </summary>
 8         private System.ComponentModel.IContainer components = null;
 9 
10         /// <summary>
11         /// 清理所有正在使用的資源。
12         /// </summary>
13         /// <param name="disposing">如果應釋放托管資源,為 true;否則為 false。</param>
14         protected override void Dispose(bool disposing)
15         {
16             if (disposing && (components != null))
17             {
18                 components.Dispose();
19             }
20             base.Dispose(disposing);
21         }
22 
23         #region Windows 窗體設計器生成的代碼
24 
25         /// <summary>
26         /// 設計器支持所需的方法 - 不要修改
27         /// 使用代碼編輯器修改此方法的內容。
28         /// </summary>
29         private void InitializeComponent()
30         {
31             this.button1 = new System.Windows.Forms.Button();
32             this.SuspendLayout();
33             // 
34             // button1
35             // 
36             this.button1.Location = new System.Drawing.Point(238, 42);
37             this.button1.Name = "button1";
38             this.button1.Size = new System.Drawing.Size(75, 23);
39             this.button1.TabIndex = 0;
40             this.button1.Text = "button1";
41             this.button1.UseVisualStyleBackColor = true;
42             // 
43             // Form1
44             // 
45             this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 12F);
46             this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
47             this.ClientSize = new System.Drawing.Size(528, 375);
48             this.Controls.Add(this.button1);
49             this.Name = "Form1";
50             this.Text = "FormMy";
51             this.ResumeLayout(false);
52 
53         }
54 
55         #endregion
56 
57         private System.Windows.Forms.Button button1;
58     }
59 }

  我們看到除了button1的聲明在form1類的下面,按鈕的實例化和屬性設置全部都是在方法InitializeComponent()中完成的,我們也可以嘗試着改改this.button1.Text = "測試按鈕";再回到界面設計器,發現同步更改了,如果我們在form1.cs中的任何的方法中更改button1的text,發現並沒有更改,所以我們可以得出一個結論,InitializeComponent()方法在設計器支持中非常的關鍵,中間的所有代碼將會影響設計器中的布局顯示。

  說完上述的內容后,您可以按F11鍵,進行分步調試,直到應用程序退出為止,這樣就對整個程序執行的過程非常清晰,一個類被實例化以后,里面的變量一定是最先執行的。

  1. Program.cs文件中的Main方法最先執行
  2. 實例化窗口,配置窗口字段
  3. 執行構造方法,加載所有的控件資源
  4. 顯示
  5. 關閉前執行dispose方法
  6. 退出Main方法。

  值得注意的是,窗體有四個常用的事件,關聯事件后如下:

 1         private void Form1_Load(object sender, EventArgs e)
 2         {
 3             MessageBox.Show("Load");
 4         }
 5 
 6         private void Form1_Shown(object sender, EventArgs e)
 7         {
 8             MessageBox.Show("Show");
 9         }
10 
11         private void Form1_FormClosing(object sender, FormClosingEventArgs e)
12         {
13             MessageBox.Show("Closing");
14         }
15 
16         private void Form1_FormClosed(object sender, FormClosedEventArgs e)
17         {
18             MessageBox.Show("Closed");
19         }

  可以將一些初始化的代碼放入到Load方法和Show方法中,區別就在於Load是在窗體顯示前執行的,這時候窗體已經實例化了,並且加載了控件,而show就是在窗體已經可以顯示時候執行的。如果在show方法中執行一些比較耗時的代碼的話,就會明顯的感覺窗體顯示出來的時候卡頓了一會,這種情況就放到load方法中比較合適。如果有退出窗體的確認或是密碼驗證的需求,可以在formClosing中編寫。下面舉個例子說明退出確認:

1         private void Form1_FormClosing(object sender, FormClosingEventArgs e)
2         {
3             if (MessageBox.Show("是否真的退出窗口?", "退出確認", MessageBoxButtons.YesNo) == DialogResult.No)
4             {
5                 e.Cancel = true;
6             }
7             //MessageBox.Show("Closing");
8         }

 

動態控件

  有時候我們希望創建一個動態的按鈕出來,就是原先它不存在的,突然有了,還可以點擊(按照道理上我們可以使用一個按鈕的Visible屬性來控制顯示和消失可以達到相似的目的),但是我們仍然需要知道控件是怎么創造出來的,比如上述項目按鈕點擊一下在旁邊生成一個新的按鈕,具體怎么生成,我們可以參照button1是怎么生成的,所以如下代碼:

 1         private void button1_Click(object sender, EventArgs e)
 2         {
 3             Button button = new Button();
 4             button.Location = new System.Drawing.Point(328, 42);
 5             button.Name = "button2";
 6             button.Size = new System.Drawing.Size(75, 23);
 7             button.TabIndex = 0;
 8             button.Text = "button2";
 9             button.UseVisualStyleBackColor = true;
10 
11             this.Controls.Add(button);
12         }

點擊之后的效果如下:

  如果我們希望按鈕2可以支持點擊事件,則稍微修改下代碼即可:

 1         private void button1_Click(object sender, EventArgs e)
 2         {
 3             Button button = new Button();
 4             button.Location = new System.Drawing.Point(328, 42);
 5             button.Name = "button2";
 6             button.Size = new System.Drawing.Size(75, 23);
 7             button.TabIndex = 0;
 8             button.Text = "button2";
 9             button.UseVisualStyleBackColor = true;
10             button.Click += Button_Click;
11 
12             this.Controls.Add(button);
13         }
14 
15         private void Button_Click(object sender, EventArgs e)
16         {
17             MessageBox.Show("你點擊了button2");
18         }

屬性說明

  我們很習慣於選擇控件后設置屬性,就像下面這張圖片一樣:

  設置光標也好,文本也罷,不知道細心的你有沒有發現,我們為什么能這樣設置,這個IDE的屬性設計器為什么能知道控件的屬性以及需要設置的數據內容,這一切的一切都被深深的藏在了底層,VS首先加載動態鏈接庫,找到控件內容,然后通過反射來獲取到屬性名稱,屬性類別,等你在上面窗口設置好新的值后,就生成相應的代碼來覆蓋原有的值。至於所有屬性的解釋,都是特性來完成的,以后在講解自定義控件的時候,再來着重說明。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM