国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 編程 > C# > 正文

.Net Winform開發(fā)筆記(一)

2020-01-24 03:36:50
字體:
供稿:網(wǎng)友
1. 理解“Windows 窗體應(yīng)用程序”項目中Program.cs文件中的main方法與傳統(tǒng)C++Console控制臺程序中的main方法的區(qū)別。從程序運行層次上講,兩者無區(qū)別,都是程序的入口點,屬于進程中的第一個線程。前者隱藏了UI應(yīng)用程序必需的消息循環(huán),后者沒有。

2. 每個Windows桌面應(yīng)用程序都必須包含至少一個UI線程,所謂UI線程,就是可以響應(yīng)Windows消息的線程。通常情況下,除非特別需要,一個Windows桌面應(yīng)用程序只包含一個UI線程。

3. UI線程本質(zhì)上跟普通線程一樣,一般為程序的入口線程,比如Program.cs文件中的main方法,就是UI線程,而Application.Run()方法中封裝了消息循環(huán)。如果沒有Application.Run()方法,那么它跟其他線程一模一樣。之所以叫做UI線程,是因為它之中包含一個類似
復(fù)制代碼 代碼如下:

While(GetMessage(…))//取Windows消息
{
//處理windows消息,調(diào)用開發(fā)者編寫的回調(diào)方法,如事件處理程序 等。
}

的循環(huán)。
4. 有關(guān)Windows消息機制等內(nèi)容,請上網(wǎng)Google或者百度。

5. UI線程主要負責(zé)界面的實時更新,所以開發(fā)人員編寫代碼時,請遵守以下規(guī)律:
1) 不要在控件的事件處理程序中編寫(或者調(diào)用)耗時的代碼塊;
2) 不要在控件的事件處理程序中調(diào)用阻塞方法;

6. 明白程序設(shè)計中的 委托、事件、事件處理程序的區(qū)別
復(fù)制代碼 代碼如下:

1) Publicdelegate void KeyPressEventHandler(KeyPressEventArgse);
2) Public eventKeyPressEventHandler KeyPress;
3) Public void Textbox1_KeyPress(objectsender,KeyPressEventArgs e)
{
//….
}

其中
1為委托 2為事件 3為事件處理程序

7. 所有的事件處理程序都是在UI線程中調(diào)用,又因為UI線程負責(zé)更新界面,所以UI線程始終必須保持順暢(表現(xiàn)為3中的while循環(huán)體不能耗時太長),即不能出現(xiàn)長時間執(zhí) 行一個方法不返回的情況。所以,請遵守5中的規(guī)律。

8. 同一個方法,可以運行在多個線程之中,方法跟線程沒有一對一的原則
復(fù)制代碼 代碼如下:

Private void thread_pro() //
{
}
1) privatebutton1_click(object sender,EventArgs e)
{
thread_pro(); //thread_pro運行在UI線程中
}
2)private button1_click(object sender,EventArgs e)
{
Thread t = new Thread(newThreadStart(thread_pro));
Thread t1 = new Thread(new ThreadStart(thread_pro));
Thread t2 = newThread(new ThreadStart(thread_pro));
t.start(); //thread_pro運行在t線程中
t1.start(); //thread_pro運行在t1線程中
t.2.start(); //thread_pro運行在t2線程中
}


3) 還可以通過Control.Invoke() 或者BenginInvoke方法將方法投遞到創(chuàng)建該控件的線程中執(zhí)行。
以上所有情況,請注意線程共享數(shù)據(jù)。

9. 多線程編程中,請注意“線程安全”問題,對于一些具備“非原子”操作的對象,必須采取措施避免發(fā)生錯誤。

UI控件(Button、datagridview等等)、集合(List、ArrayList)等屬于此類對象,控件任何時間都不能多線程訪問。

10. 堅決杜絕跨線程訪問UI控件,原因見9。跨線程訪問控件的方法見8中的3)。

11. 除了.Net Winform中的事件處理程序是在UI線程中調(diào)用以外,其它的回調(diào)方法幾乎所有都不會在UI線程中執(zhí)行,所以,開發(fā)人員在編寫回調(diào)方法時,請遵守第9,10兩大規(guī)律。

12. 明白什么叫回調(diào)方法。回調(diào)方法一般由開發(fā)者編寫,但不由開發(fā)者調(diào)用,由系統(tǒng)(或者說框架)調(diào)用。在Windows桌面應(yīng)用程序開發(fā)過程中,控件的事件處理程序都屬于回調(diào)方法,回調(diào)方法一般用在“觀察者”設(shè)計模式中,當事件的激發(fā)者激發(fā)一個事件時,它就會調(diào)用回調(diào)方法。控件的所有事件都屬于此類。
另外一種常見為,異步執(zhí)行某個操作,譬如,socket.BeginAccept()中的AsyncCallBack類型參數(shù)。
在框架橫行的時代,一般開發(fā)者編寫的代碼都屬于回調(diào)代碼。因為程序的主要結(jié)構(gòu)都由先輩們在框架中集成好了。開發(fā)者們只需要像填空一樣完善空缺的部分。

13. 阻塞方法指,由于方法體內(nèi)包含耗時較長的操作,所以方法不能及時返回。
所謂“及時”與“非及時”沒有絕對界限,示例如下:
復(fù)制代碼 代碼如下:

int func1() //及時返回
{
Int index = 0;
For(int i=0;i<100;i++)
{
Index ++;
}
Return index;
}
Int func2() //非及時返回
{
Int index = 0;
For(int i=0;i<1000;i++)
{
For(int j=0;j<1000;++j)
{
Index ++;
}
}
Return index;
}

上述func1相對而言,屬于非阻塞方法,func2屬于阻塞方法。

14. Windows窗體應(yīng)用程序不會直接跟鍵盤、鼠標等硬件設(shè)備交互,它只與Windows消息有直接交互。雖然表面上鼠標鍵盤等硬件設(shè)備是操作在窗體之上的,但實質(zhì)上,你 編寫的桌面應(yīng)用程序是不會理解這些硬件設(shè)備的一舉一動。他們是通過操作系統(tǒng)(驅(qū)動程序)進行橋接的,操作系統(tǒng)先將硬件設(shè)備的一舉一動翻譯成windows消息(一種數(shù)據(jù)結(jié)構(gòu),程序可以理解),然后供程序理解,作出相應(yīng)的反應(yīng)。
15. 所謂“阻塞調(diào)用線程”,是指在某一個線程中調(diào)用了阻塞方法,從而使該線程不能及時執(zhí)行以后的代碼。
復(fù)制代碼 代碼如下:

Void func()
{
Int index=0;
For(int i=0;i<10000;++i)
{
For(int j=0;j<10000;++j)
{
I ndex++;
}
}
}
Thread t = newThread(new ThreadStart(func));
t.Start(); //線程t中調(diào)用了阻塞方法func,因此線程t會被阻塞

在介紹func方法時,可以這樣描述:該方法會阻塞調(diào)用線程。

16. 同一個方法可以被多個線程調(diào)用,既可被UI線程調(diào)用,也可被非UI線程調(diào)用,那么在方法體內(nèi)怎么編寫訪問UI控件(UI元素)的代碼呢?(跨線程訪問UI控件會引發(fā)異常)
復(fù)制代碼 代碼如下:

Void func()
{
Textbox1.Text=”測試”;
PictureBox1.Image = Image.FromFile(“a.jpg”);
}

1)以上func方法可能運行在UI線程中,如下:
復(fù)制代碼 代碼如下:

Private voidbutton1_Click(object sender,EventArgs e)
{
func(); //調(diào)用func方法
}

2)有如下,func方法可能運行在其他非UI線程中
復(fù)制代碼 代碼如下:

Private void button1_Click(object sender,EventArgs e)
{
Thread t = new Thread(newThreadStart(func));
t.Start(); //func訪問運行在t線程中
}

在2)中,可能引發(fā)異常。
以上問題的解決方案為:
修改func代碼為:
復(fù)制代碼 代碼如下:

Func()
{
If(this.InvokeRequired)
{
This.BeginInvoke((Action)delegate(){func()});
}
Else
{
Textbox1.Text=”測試”;
PictureBox1.Image = Image.FromFile(“a.jpg”);
}
}

有關(guān)BeginInvoke或者Invoke方法的使用,請上網(wǎng)Google或者百度。

17. 有關(guān)“跨線程訪問UI控件可能引發(fā)異常”的原因,跟多線程訪問集合可能出現(xiàn)錯誤的原因基本相似。下面列舉一段代碼說明情況
復(fù)制代碼 代碼如下:

ClassMyControl
{
Object root;
Public Draw()
{
GetRoot(root);
// 一系列操作…
ReleaseRoot(root);
}
Public OtherDraw()
{
GetRoot(root);
// 一系列操作 …
ReleaseRoot(root);
}
}

其中root變量同時只能被占用一次,GetRoot()獲取root的訪問權(quán),如果root已經(jīng)被占用,則拋出異常。ReleaseRoot()釋放root占用。

當在一個線程中(比如UI線程中)訪問MyControl類對象A,調(diào)用A.Draw()方法,執(zhí)行到GetRoot(root)方法后,該線程失去控制權(quán),暫停運行一下的代碼,即此時root已被占用。而另一線程中如果也要訪問同一對象A的Draw()方法,那么就會引發(fā)異常。

18.在.Net Winform應(yīng)用程序中,程序與用戶的交互主要包含兩個方面,一是用戶用鼠標、鍵盤燈硬件設(shè)備進行操作,程序響應(yīng)操作,然后進行反饋(比如更新界面、刷新數(shù)據(jù)等),二是不需要用戶用鼠標等硬件設(shè)備進行操作,程序自己自動進行反饋(比如QQ彈出新聞窗體、360彈窗等)。

第一種情況是我們所熟知的,比如用戶用鼠標點擊按鈕(button1),程序則彈出一個MessageBox,我們在程序中是這樣子寫的:事件處理程序如下
復(fù)制代碼 代碼如下:

Private voidbutton1_Click(object sender,EventArgs e)
{
MessageBox.Show(“彈出對話框,或者其他操作”);
}

再來理一下這個過程,首先用戶拿起鼠標點擊button1,操作系統(tǒng)(鼠標驅(qū)動)會捕獲這個事件,經(jīng)過分析,操作系統(tǒng)得知用戶點擊的是哪個窗體(按鈕)、點擊的位置(坐標),點擊類型(左鍵還是右鍵或者其他),以及其他信息,之后,將這些信息封裝成一個類型(即windows消息)發(fā)送給創(chuàng)建該窗體(控件)的線程中的消息隊列,之后,操作系統(tǒng)(鼠標驅(qū)動)就不在負責(zé)了。接著,UI線程從線程消息隊列中獲取該消息(注意:這個過程是一直存在的),分析消息,調(diào)用開發(fā)人員編寫的一些回調(diào)方法,如button1_Click()方法,從而到達相應(yīng)鼠標鍵盤操作的目的。從上面分析過程來看,再一次說明,程序是不會直接跟鼠標等硬件設(shè)備交互的,與它直接交互的只有Windows消息,而這個過程需要Windows操作系統(tǒng)起著重要作用。

第二種情況一般用在多線程編程中,當程序有耗時操作、或者需要一直監(jiān)聽等情況的時候,是不能放在UI線程之中的,這時候就需要另外開辟線程,在另外的線程中處理。這種情況中,另外開辟的線程有時候需要反饋跟用戶一些信息,即更新UI界面或者彈出一個窗體等,這就涉及到跨線程訪問UI元素的問題了,詳見5和

19.以上代碼部分均為現(xiàn)寫的,可能出現(xiàn)拼寫錯誤,包涵!
另外,請配合筆記(二)中的“DOT NETWinform應(yīng)用程序運行結(jié)構(gòu)圖”閱讀。
發(fā)表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發(fā)表
主站蜘蛛池模板: 黄龙县| 桃江县| 双柏县| 澎湖县| 滨海县| 潞西市| 长垣县| 冀州市| 独山县| 梁山县| 长宁区| 上虞市| 无为县| 永福县| 依安县| 西乌珠穆沁旗| 布拖县| 阿瓦提县| 邯郸市| 和硕县| 商洛市| 大渡口区| 西乌珠穆沁旗| 吉木乃县| 石阡县| 南丰县| 贵定县| 澄江县| 迁西县| 翁牛特旗| 轮台县| 通渭县| 平陆县| 类乌齐县| 门头沟区| 榆社县| 阿拉善右旗| 多伦县| 苏尼特左旗| 寻甸| 寻甸|