自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

探討WinForm不同代碼的實(shí)現(xiàn)

開發(fā) 后端
本文將通過對(duì)不同方法的WinForm代碼進(jìn)行對(duì)比,希望能對(duì)大家更好的了解WinForm有所幫助。

WinForm看上去有些深?yuàn)W,在這里我們將探討WinForm二三事,希望通過以下的文字,能讓大家在開發(fā)過程中對(duì)WinForm有更深入的了解和認(rèn)識(shí)。

在進(jìn)入正文之前,想請(qǐng)大家先欣賞下面兩段代碼:

  1. //這是一個(gè)控制臺(tái)程序,請(qǐng)先添加System.Windows.Form.dll的引用   
  2. using System.Windows.Form;       
  3. public class ConsoleApplicationShowDialog    
  4. {     
  5.    static void Main()    
  6.     {     
  7.         Form frm = new Form();    
  8.        frm.ShowDialog();    
  9.   }    
  10.  }    

兩個(gè)代碼片段都是控制臺(tái)程序(編譯的時(shí)候,請(qǐng)選擇ConsoleApplication類型編譯)。這兩段程序***的區(qū)別就在于顯示窗體的時(shí)候***個(gè)使用ShowDialog(就是所謂的模態(tài)窗體),第二個(gè)使用Show(也就是所謂的非模態(tài)窗體)。

經(jīng)過測(cè)試我們發(fā)現(xiàn),使用Show顯示出來的窗體一顯示就死在那里了,不響應(yīng)用戶的輸入,如果你在窗體上放一個(gè)按鈕,甚至發(fā)現(xiàn)按鈕都無法顯示,點(diǎn)擊也無任何響應(yīng)。而是用ShowDialog顯示出來的窗體卻不一樣,可以響應(yīng)用戶的輸入。這是什么原因呢?

為了找到問題的根源,我們來看看Show方法和ShowDialog方法實(shí)現(xiàn)的區(qū)別。Show方法是在Control里定義的,F(xiàn)orm間接的派生自Control類(看起來這里是一個(gè)組合模式哦),Show方法代碼:

  1. public void Show()    
  2.  {     
  3.      this.Visible = true;    
  4.  }  

Show方法的代碼相當(dāng)?shù)暮?jiǎn)單,做的工作僅僅就是將窗體顯示出來,那前面第二段代碼應(yīng)該與下面的代碼作用是一樣的:

  1. //這是一個(gè)控制臺(tái)程序,請(qǐng)先添加System.Windows.Form.dll的引用     
  2.  using System.Windows.Form;   
  3. public class ConsoleApplicationShow     
  4. {    
  5.   static void Main()   
  6.     {     
  7.         Form frm = new Form();    
  8.     frm.Visible = true;   
  9.   }    

現(xiàn)在再來看看ShowDialog方法,ShowDialog方法有些復(fù)雜,但是在這百來行代碼中,應(yīng)該有一條你很熟悉:

  1. public DialogResult ShowDialog(IWin32Window owner)     
  2. {     
  3.     //...省略     
  4.      Application.RunDialog(this);     
  5.     //...省略     
  6.  } 

哦,這行代碼跟我們千千萬萬個(gè)WinForm程序的啟動(dòng)部分相當(dāng)類似:

  1. public class Program     
  2. {     
  3.    static void Main()     
  4.      {    
  5.          Form frm = new Form();     
  6.          Application.Run(frm);    
  7.     }     
  8. }  

MSDN對(duì)Application.Run的說明是:

Begins running a standard application message loop on the current thread, and makes the specified form visible.在當(dāng)前的線程上啟動(dòng)一個(gè)標(biāo)準(zhǔn)的應(yīng)用程序“消息循環(huán)”,并且顯示指定的窗體,下面是Application.Run的代碼:

  1. public static void Run(Form mainForm){    
  2. ThreadContext.FromCurrent().RunMessageLoop(-1, new   
  3. ApplicationContext(mainForm));  
  4. }  

哦?什么是消息循環(huán)?如果你是直接進(jìn)入.Net開發(fā)的,沒有經(jīng)過Win32時(shí)代的洗禮,那可能對(duì)這個(gè)消息循環(huán)并不是很清楚,在你眼里只有注冊(cè)事件,處理事件。雖然.Net通過封裝,簡(jiǎn)化了消息循環(huán)這種處理用戶點(diǎn)擊等事件的編程模型,但是.Net底下還是Win32,有的時(shí)候我們還是得了解一下,對(duì)理解有些問題可能有幫助(后面會(huì)提到)。

消息循環(huán)(Message Loop)

說Application.Run啟動(dòng)一個(gè)消息循環(huán),那么什么是消息循環(huán)呢?看下面的代碼:

  1. MSG msg;   
  2. while(GetMessage(&msg,NULL,0,0)){   
  3.    TranslateMessage(&msg);      
  4. DispatchMessage(&msg);  

這是一段幾乎所有使用Win32 API編寫Windows Application的程序里都有的代碼。這就是一個(gè)消息循環(huán)。你不需要透徹的理解上面這段代碼,你只需要了解這么一個(gè)意思:

Windows為每個(gè)Windows程序都維護(hù)了一個(gè)消息隊(duì)列,當(dāng)有用戶輸入事件的時(shí)候,Windows就把這個(gè)事件轉(zhuǎn)換為一個(gè)稱之為“消息”的東東(也就是上面代碼中的MSG結(jié)構(gòu)),在這個(gè)消息里包含有一些信息,比如鼠標(biāo)點(diǎn)擊的點(diǎn)啊,消息的類型啊等等。而上面的while循環(huán)中的GetMessage方法就是不斷的從這個(gè)消息隊(duì)列里取消息出來,然后處理,這樣窗體就能響應(yīng)用戶的輸入了。

通過上面的討論,我們現(xiàn)在大概明白了為啥Show和ShowDialog區(qū)別這么大呢,原來ShowDialog啟動(dòng)了一個(gè)消息循環(huán),這樣用ShowDialog顯示出來的窗體就能響應(yīng)用戶的輸入事件了,而Show僅僅是設(shè)置一下窗體的Visible屬性,并沒有啟動(dòng)一個(gè)消息循環(huán),使用Show顯示出來的窗體也就無法響應(yīng)用戶的輸入事件了,也就是死在那里了。

上面說,GetMessage取出消息,然后處理,那在哪兒處理呢?在Win32程序中我們還可以看到這樣的片段:

  1. LRESULT CALLBACK WndProc(HWND hwnd,UINT message,WPARAM   
  2. wParam,LPARAM lParam){   
  3.    switch(message)    {        
  4.   case WM_CREATE:            //處理窗體創(chuàng)建事件                
  5.  return 0;          
  6. case WM_PAINT:            //處理窗體繪制事件              
  7. return 0;                //更多事件,比如按鈕點(diǎn)擊等      
  8. }  

啊,好丑陋的處理方式。原來是根據(jù)message的類型,做出不同的處理,而Windows定義了一大堆WM_開頭的東東??晌覀兛蓯鄣?Net,WinForm里面優(yōu)美的事件處理模型就是基于這個(gè)之上的,通過上面的代碼,和你在.Net里使用事件的感觸你是否能想象出.Net是如何封裝這個(gè)過程的?

WinForm中的消息處理

實(shí)際上在.Net的WinForm中,消息處理的影子還是存在的,并沒有消失得無影無蹤,在Form中還有這么一個(gè)protected的方法:

  1. protected override void WndProc(ref Message m){   
  2.    switch (m.Msg)    {          
  3. case 0x10://......          
  4. case 0x11:        //....     
  5.  }      
  6. base.WndProc(ref m);} 

哦,原來與Win32里面的那個(gè)一模一樣。實(shí)際上通過重寫這個(gè)方法我們可以實(shí)現(xiàn)一些正常做法難以實(shí)現(xiàn)的東東。

為什么耗時(shí)操作要異步

談了這么多,我們來談一點(diǎn)我們身邊的事情。你應(yīng)該碰到過這樣一個(gè)場(chǎng)景:編寫一個(gè)程序,點(diǎn)擊一個(gè)按鈕之后要做一個(gè)比較耗時(shí)的操作,比如要更新一大批數(shù)據(jù)到數(shù)據(jù)庫,這個(gè)時(shí)候程序就像本文開頭那個(gè)程序一樣,死掉了。用戶不管怎么點(diǎn)擊,程序變成灰色,標(biāo)題欄上還顯示一個(gè)“沒有響應(yīng)”,有的程序甚至連個(gè)提示都不給,用戶以為真的死掉了,氣急敗壞的啪嚓一下把程序關(guān)了,耗時(shí)操作進(jìn)行到一半就這樣被無情終止。這是為什么呢?

通過前面的討論,我們知道,響應(yīng)用戶的輸入就是靠消息循環(huán),而消息循環(huán)就是在當(dāng)前的線程上,也就是我們所謂的那個(gè)UI線程,如果一個(gè)耗時(shí)操作也同在UI線程上,那么消息循環(huán)就“卡著”了,也就無法處理后續(xù)的消息,程序也就假死了。

那我們?nèi)绾翁幚磉@種耗時(shí)操作呢?當(dāng)然就是將這個(gè)耗時(shí)操作放到另外一個(gè)線程中,不占用UI線程,讓消息循環(huán)得以繼續(xù)的進(jìn)行下去。

原文標(biāo)題:WinForm二三事

鏈接:http://www.cnblogs.com/yuyijq/archive/2009/11/04/1595775.html

責(zé)任編輯:彭凡 來源: 博客園
相關(guān)推薦

2019-06-03 09:00:25

Kubernetes部署金絲雀版本

2024-08-20 08:05:14

WinformWndProc?Windows

2024-04-19 00:47:07

RabbitMQ消息機(jī)制

2010-12-22 11:19:09

Java字節(jié)代碼

2009-12-02 19:42:24

PHP頁面自動(dòng)跳轉(zhuǎn)

2024-10-10 08:32:28

Redis高并發(fā)Lua

2009-12-01 16:34:21

PHP表單

2024-05-11 08:20:23

2009-11-23 10:31:25

PHP使用JSON

2009-11-30 18:59:52

PHP數(shù)組排序

2009-09-01 10:35:59

C# WinForm控

2010-01-04 17:29:00

Silverlight

2010-02-03 10:50:33

C++多態(tài)

2022-02-21 08:18:38

option編程模式

2009-09-03 17:01:04

C#回車切換焦點(diǎn)

2024-10-15 16:01:19

SpringBoot緩存預(yù)熱

2010-01-20 09:14:49

C語言模塊化

2009-11-30 17:49:51

PHP函數(shù)preg_s

2021-01-05 13:23:39

數(shù)據(jù)中心數(shù)據(jù)中心節(jié)能碳中和

2012-08-21 11:26:17

Winform
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)