.NET尋根問底之表單Resize事件

來源:互聯網
上載者:User

.NET尋根問底之表單Resize事件


今天收到一名名為“三十而悟”的中專學校的電腦教師同行的郵件:

=====================================================

我最近正在把我掌握的有關Visual Basic的一些教學和開發經驗寫成一本書,目前寫了20多萬字了。在寫的過程中,發現存在一個很有意思的問題,一直百思不解。特向您請教一下。

問題描述:在Visual Basic 2005的IDE環境下,我使用的IDE是Visual Studio 2005 Team Suite,環境設定選的是“Visual Basic開發設定”。在表單的兩個事件Resize和Load出現的先後順序中出現的問題。按理說,這兩個事件,Load一定是發生於Resize事件之前的。但是,我在編寫代碼過程中,有一次偶然的機會,發現Resize事件是發生在Load之前,我百思不得其解。在花了一天的時間找原因時,才重現了這種Resize發生於Load之前的情境。我發現,如果在表單設計階段,重新調整一下表單的大小不按預設的300*300的大小設定,則Resize事件必發生在Load事件之前。我雖然重現了這種情況,但我找不出這種情況出現的原因。
當然如果一定要在Resize事件和Load事件中寫代碼且要區分他們的先後,用一個開關量是可以解決的。只是問題放在心裡特不好受,網上也找了很多資料,就是沒辦法解決。只能向您發送一個請教了,您畢竟是同行中專家。打擾之處,請原諒!

來自一個中專學校的電腦教師同行

敬上,謝謝!

=================================================

我開啟Visual Studio,檢測了一下,真的如他所說。這也引發了我的興趣,產生這種現象的原因何在?

查詢MSDN未獲直接答案,我覺得必須到.NET原始碼中去找謎底。

以下是我的追尋之路:

首先,我發現Form類定義了一個DefaultSize屬性:

protected override Size DefaultSize

{

get

{

return new Size(300, 300);

}

}

可以看到,它設定的預設屬性就是300*300.

然後,我在Form類的基類Control的建構函式中找到以下代碼:


internal Control(bool autoInstallSyncContext)
{
……

Size defaultSize = this.DefaultSize;
this.width = defaultSize.Width;
this.height = defaultSize.Height;
……
}

可以看到,在建構函式中表單的高度和寬度被定義為預設值。

開啟Visual studio自動產生的的Form1.Designer.vb,可以看到以下代碼:


Private Sub InitializeComponent()
Me.SuspendLayout()
'
'Form1
'
Me.AutoScaleDimensions = New System.Drawing.SizeF(6.0!, 12.0!)
Me.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font
Me.ClientSize = New System.Drawing.Size(562, 415)
Me.Name = "Form1"
Me.Text = "Form1"
Me.ResumeLayout(False)

End Sub

這說明表單的ClientSize屬性已經被改為預設值(300,300)之外的數值 。

ClientSize是一個屬性,給它賦值時會調用SetClientSizeCore方法。

public Size ClientSize
{
    get
    {
        return new Size(this.clientWidth, this.clientHeight);
    }
    set
    {
        this.SetClientSizeCore(value.Width, value.Height);
    }
}

SetClientSizeCore方法內部又調用SizeFromClientSize方法設定表單的Size屬性:

protected virtual void SetClientSizeCore(int x, int y)
{
    this.Size = this.SizeFromClientSize(x, y);
    this.clientWidth = x;
    this.clientHeight = y;
    this.OnClientSizeChanged(EventArgs.Empty);
}

Size屬性內部調用SetBounds方法

public Size Size
{
    get
    {
        return new Size(this.width, this.height);
    }
    set
    {
        this.SetBounds(this.x, this.y, value.Width, value.Height, BoundsSpecified.Size);
    }
}

SetBounds方法又經過幾個方法調用(不再贅述),最終調用UpdateBounds方法。

在Form類的UpdateBounds方法中,可以看到以下代碼:



protected void UpdateBounds(int x, int y, int width, int height, int clientWidth, int clientHeight)
{   
 。。。
  bool flag2 = ((( this.Width != width) || (this.Height != height)) || (this.clientWidth != clientWidth)) || (this.clientHeight != clientHeight);    
 this.x = x;    this.y = y;    this.width = width;    this.height = height;    
this.clientWidth = clientWidth;    this.clientHeight = clientHeight;    
。。。
if ( flag2)    {      
  this. OnSizeChanged(EventArgs.Empty);     
 。。。
  }
。。。

可以看到,只要尺寸不等於300*300,就會調用OnSizeChanged方法,而此方法負責激發Resize事件。


那麼,UpdateBounds方法在什麼情況被調用?

使用Reflector繼續跟蹤下去,可以看到,位於最頂層的並且間接調用它的語句在WmCreate()方法中,而此方法又位於表單過程WndProc內。

protected virtual void WndProc(ref Message m)
{
    if ((this.controlStyle & ControlStyles.EnableNotifyMessage) == ControlStyles.EnableNotifyMessage)
    {
        this.OnNotifyMessage(m);
    }
    switch (m.Msg)
    {
        case 1:
            this.WmCreate(ref m);
            return;

        case 2:
            this.WmDestroy(ref m);
            return;

。。。
}
。。。
}

在表單過程WndProc中,響應表單建立訊息(WM_CREATE)時,就會調用WmCreate()方法。WM_CREATE訊息在表單建立時由Windows負責發送給進程。所以,經過刨根問底的一番尋根之旅,我們弄明白了產生這一現象的根本原因。

感想:
微軟平台的技術大都有這樣的一個特點:抽象層次較高,使用簡易。但封裝層次很多,表面的“簡單”是由背後的“複雜”所支撐。很多使用微軟技術的程式員習慣了“只管用,不管為什麼”,其實這種工作與學習方式並不利於技術的進一步提升。

就本文所討論的問題而言,雖然Resize事件激發順序問題在實際開發中可能並不十分重要與關鍵,但這種技術探索精神很可貴。如果學技術、教技術、用技術的人都有這種探索勁頭,杜絕浮燥的急功近利的風氣,相信國內軟體開發人員的總體水平絕不會差。

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.