2012-02-17 128 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); 
} 

这将这样的伎俩。至少在我的机器上工作:-)