2012-02-17 127 views
1

我有一個最小高度設置的表單,因爲我不想在「簡約顯示」模式下調整大小超出特定點的大小。從WM_SIZE消息更改表單大小

當用戶嘗試通過Aero將窗口最大化並將其捕捉到屏幕頂部時,窗口被最大化,但窗口的高度僅爲240像素(設置的最大尺寸)。如果我在wParamSIZE_MAXIMIZED時嘗試處理WM_SIZE消息,則繞過了設置表單高度的任何嘗試。

目前我正在處理SC_MAXIMIZE來檢測何時按下最大化按鈕,並且WM_NCLBUTTONDBLCLK如果用戶雙擊標題欄以最大化窗口。在這兩種情況下,我都可以切換擴展窗口模式並設置最小尺寸,以便能夠全屏顯示。

當然,如果窗口通過ShowWindow(SW_MAXIMIZE)最大化或者當屏幕上出現aero-snap時,這些消息都不會發布。

我能處理的另一個消息是在系統實際進行最大化之前發生的,所以我可以事先調整窗口大小和顯示模式?

目前代碼:

protected override void WndProc(ref Message m) 
{ 
    if (m.Msg == 0x0112) { // WM_SYSCOMMAND 
     if (m.WParam == new IntPtr(0xF030)) { // Maximize event - SC_MAXIMIZE from Winuser.h 
      // The window is being maximized 
      this.MaximumSize = new Size(9999, 9999); 
      ToggleDeviceDisplay(true); 
      linkToggleDeviceList.Visible = false; 
     } 
    } else if (m.Msg == 0x00A3) { // WM_NCLBUTTONDBLCLK - Double clicking on window title bar, min or max 
     if (this.WindowState == FormWindowState.Normal) { 
      if (grpDeviceList.Visible == false) { 
       this.MaximumSize = new Size(9999, 9999); 
       ToggleDeviceDisplay(true); 
      } 
      this.WindowState = FormWindowState.Maximized; 
      linkToggleDeviceList.Visible = false; 
     } else { 
      this.WindowState = FormWindowState.Normal; 
      linkToggleDeviceList.Visible = true; 
     } 
     return; 
    } else if (m.Msg == 0x0005) { // WM_SIZE 
     if (m.WParam == new IntPtr(0x02)) { // SIZE_MAXIMIZED 
      // CANT GET WINDOW TO GO TO FULL-SCREEN FROM HERE 
      this.MaximumSize = new Size(9999, 9999); 

      // THE LINE BELOW DOESN'T WORK, probably because it is already being sized 
      this.Height = Screen.FromHandle(this.Handle).WorkingArea.Size.Height; 
     } else if (m.WParam == new IntPtr(0x00)) { // SIZE_RESTORED 
      linkToggleDeviceList.Visible = true; 
     } 
    } 
    base.WndProc(ref m); 
} 

如果窗口已經處於當WM_SIZE最大限度地發送擴展顯示模式,是沒有問題的,因爲最大窗口大小設置爲允許全屏,但是,如果他們試圖從最小模式最大化,我不能讓應用程序切換到消息過程中佔用全屏。

我知道我可以觸發一個計時器或從消息中運行的東西,所以它會很快調整大小,用戶不會立即注意到它不是全屏,但這只是一個可怕的破解。

編輯:

爲了說明這兩個窗口狀態,我已經上傳兩張截圖here。頂部圖像顯示擴展顯示,對窗口大小沒有限制,底部圖像顯示最小顯示,它具有高度限制設置,因此它們無法增加窗口的高度,因爲它只會顯示更多的空白空間。

謝謝。

+0

爲什麼不使用實際的窗口消息常量值,比如'WM_SIZE'而不是十六進制值? – kprobst 2012-02-17 22:48:33

+0

沒有什麼好的理由,起初我只使用2條消息,所以我使用了這些值,而不是像我應該那樣在應用中定義它們。 – drew010 2012-02-17 22:53:01

+2

從Windows的角度來看,「窗口高度不得超過Y像素,除非用戶希望使其更大,然後可能更大」的概念是愚蠢的。窗口高度限制爲Y像素,否則不是。你不能兩面都有。 – hvd 2012-02-18 00:06:46

回答

2

在我看來,你想以一種過於複雜的方式做一件簡單的事情。我會處理WM_GETMINMAXINFO message,每當它的大小或位置即將更改時,它會發送到您的窗口。處理這個消息讓你有機會爲每個屬性指定最大值或最小值,有效地防止它變得比你想要的更小或更大。

我不會發布很多示例代碼,因爲您的問題表明您已經知道如何覆蓋WndProc並處理窗口消息。您需要做的唯一事情就是在託管代碼中定義MINMAXINFO結構。事情是這樣的:

[StructLayout(LayoutKind.Sequential)] 
struct POINT 
{ 
    public int X; 
    public int Y; 
} 

[StructLayout(LayoutKind.Sequential)] 
struct MINMAXINFO 
{ 
    public POINT ptReserved; 
    public POINT ptMaxSize; 
    public POINT ptMaxPosition; 
    public POINT ptMinTrackSize; 
    public POINT ptMaxTrackSize; 
} 

使用Marshal.PtrToStructure包含在Message.LParam財產指針轉換爲上述定義的MINMAXINFO結構的一個實例。所以,你的WndProc方法裏面,你會做這樣的事情:

MINMAXINFO mmi = (MINMAXINFO)Marshal.PtrToStructure(msg.LParam, typeof(MINMAXINFO)); 

更新:

從您發佈的截圖,它看起來像兩個不同的顯示器是相同的,唯一的區別是顯示底部的DataGridView。顯示頂部的GroupBox,無論表單的大小如何。

因此,在我看來,解決辦法很簡單,就是處理Form.Resize事件(這應該提高不管你的形式是如何調整,無論是通過手動拖動邊框,點擊標題欄按鈕,或用Aero Snap)。

在該事件處理程序方法中,檢查窗體的當前尺寸。如果它足夠大,請將DataGridView控件的Visible屬性設置爲true。如果尺寸不夠,請通過設置DataGridView.Visible = false切換到「最小模式」。

這不是一個技術上非常複雜的解決方案,但它似乎應該完成所有您想要的目標。我理解的動機只是當表單太小而無法看到所有內容時提供更簡單的接口,並且在表單較大時擴展該接口。如果您處理Resize事件,並在該事件觸發後檢查表單的實際大小,則不會出錯。

另一種解決方案是啓用AutoScroll屬性並始終顯示兩個控件。所有用戶只需向上或向下滾動即可查看他們想要的任何內容。 WinForms負責其餘部分。

+0

我不久前開始嘗試使用'WM_GETMINMAXINFO',因爲我認爲它可能是一種好的方式。現在唯一的問題是Windows在移動窗口或嘗試調整窗口大小時發送該消息。如果應用程序處於最小模式,我想說最大尺寸是較小的尺寸,但是當他們嘗試空氣對齊時,我需要欺騙它以考慮最大尺寸是顯示器的尺寸。現在我只是無法知道如何知道消息何時傳入,因爲移動/調整大小與Aero詢問最大尺寸有多大。 – drew010 2012-02-18 00:08:25

+0

@drew:我不確定我瞭解動機。無論如何,Aero Snap不會比屏幕大。 – 2012-02-18 00:16:16

+0

查看屏幕截圖[here](http://imgur.com/a/Zap2C)。問題是,在最小模式下,在窗口上設置高度限制時,航空捕捉最大化窗口,但高度仍然只有〜300像素。我想以某種方式將窗口大小增加到屏幕大小,並同時啓用擴展顯示。使用'SC_MAXIMIZE'和'WM_NCLBUTTONDBLCLK'很好,但是aero snap只會在WM_SIZE消息使我的窗口最大化之後(使用更小的高度)發佈消息。在WM_SIZE中,我似乎無法改變高度,只是忽略了調整大小。 – drew010 2012-02-18 00:44:29

2

我的理解是否正確:您是否希望窗口具有最小允許尺寸並能夠最大化?如果那樣的話,你的代碼太複雜了,而且實際上並不需要。只需使用窗口的屬性MinimumSize即可。

+0

我確實設置了最小尺寸,但是當窗口處於最小顯示模式時,我不希望它能夠調整到超出某個高度,這就是爲什麼我設置了最大尺寸限制的原因。問題是,如果它們處於最小模式,並且使用Aero Snap最大化窗口,我似乎無法找到在最大化之前增加最大尺寸的方法。 – drew010 2012-02-17 22:36:19

+0

然後看到我的下一個答案。 – 2012-02-19 09:58:27

1

所以你希望你的表單具有最小尺寸,最大尺寸,並且仍然能夠使用標題欄雙擊,最大化按鈕和Aero捕捉使其最大化?棘手:-)這是解決方案。

設置你的minimumSize屬性,然後寫2個事件:

private void Form1_Resize(object sender, EventArgs e) 
{ 
    if (WindowState == FormWindowState.Normal) 
    { 
     MaximumSize = new Size(maxWidth, maxHeight); 
    } 
} 

和:

private void Form1_ResizeEnd(object sender, EventArgs e) 
{ 
    MaximumSize = new Size(0, 0); 
} 

這將這樣的伎倆。至少在我的機器上工作:-)