3

为 COMPILED 应用程序激活 Aero 时,如何使用 VBNET 或 C# 代码正确确定非客户区大小?(是的,这个问题只发生在运行编译的应用程序时,而不是从 IDE 启动应用程序时

当我调整表单大小或执行与表单的高度/宽度相关的任何操作时,我永远不会得到预期的结果。

例如这是一个简单的两种形式的对接代码的一部分:

VB-NET:

Me.Location = New Point((form1.Location.X + form1.Width), form1.Location.Y)

C#:

this.Location = new Point((form1.Location.X + form1.Width), form1.Location.Y);

举个例子,我将展示我的一个程序。

上面的代码在 Aero 未激活时运行完美:

在此处输入图像描述

...但是如果 Aero 被激活,那么结果如下:

在此处输入图像描述

请注意右侧的表单如何位于左侧表单的非客户端边框下方。

...或者这是左侧表单位于右侧表单的非客户端边框下方的其他图像:

在此处输入图像描述

我的问题是解决这个问题的方法是什么?

更新:

扩展框架解决方案不起作用。

表格1:

Imports System.Runtime.InteropServices

Public Class Form1
    Public Moving_From_Secondary_Form As Boolean = False

    <DllImport("dwmapi.dll")> _
    Private Shared Function DwmExtendFrameIntoClientArea(ByVal hwnd As IntPtr, ByRef margins As MARGINS) As Integer
    End Function

    <StructLayout(LayoutKind.Sequential)> _
    Public Structure MARGINS
        Public leftWidth As Integer
        Public rightWidth As Integer
        Public topHeight As Integer
        Public bottomHeight As Integer
    End Structure

    Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
        Dim margins As New MARGINS()
        margins.leftWidth = -1
        margins.rightWidth = -1
        margins.topHeight = -1
        margins.bottomHeight = -1
        DwmExtendFrameIntoClientArea(Me.Handle, margins)
        Form2.Show()
    End Sub

    Private Sub Form1_Move(ByVal sender As Object, ByVal e As System.EventArgs) Handles MyBase.Move
        If Not Moving_From_Secondary_Form Then Form2.Location = New Point(Me.Right, Me.Top)
    End Sub

End Class

表格2:

Public Class Form2

    Private Sub Form2_Move(ByVal sender As Object, ByVal e As System.EventArgs) Handles MyBase.Move
        Form1.Moving_From_Secondary_Form = True
        Form1.Location = New Point(Me.Left - Form1.Width, Me.Top)
        Form1.Moving_From_Secondary_Form = False
    End Sub

End Class

结果:

在此处输入图像描述

另外我想记住: 这个问题只发生在运行编译的应用程序时,而不是从 IDE 启动应用程序时

**

更新:

**

测试了 GetWindowRect 解决方案,总是返回一个 0,对我不起作用,也许我做错了什么:

Imports System.Runtime.InteropServices

Public Class Form1

    Private Declare Function GetWindowRect Lib "user32" (ByVal Handle As IntPtr, Rect As RECT) As Long
    Private Declare Function CopyRect Lib "user32" (DestRect As RECT, SourceRect As RECT) As Long

    <StructLayout(LayoutKind.Sequential)> _
    Structure RECT
        Public Left As Int32
        Public Top As Int32
        Public Right As Int32
        Public Bottom As Int32
    End Structure

    Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
        Form2.Show()
    End Sub

    Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
        Dim rectWindow As RECT, rectCopy As RECT

        'Get the bounding rectangle of this window
        GetWindowRect(Me.Handle, rectWindow)
        'Copy the rectangle
        CopyRect(rectCopy, rectWindow)

        MsgBox("This form's width:" & (rectCopy.Right - rectCopy.Left).ToString & " pixels")
        Form2.Location = New Point(rectCopy.Right, rectCopy.Top)
    End Sub

End Class

**

更新:

**

再次尝试使用 GetWindowRect,这次代码正确编写但没有解决问题:

Imports System.Runtime.InteropServices

Public Class Form1
    <StructLayout(LayoutKind.Sequential)> _
    Private Structure RECT
        Public Left As Int32
        Public Top As Int32
        Public Right As Int32
        Public Bottom As Int32
    End Structure

    Private Declare Function GetWindowRect Lib "user32" (ByVal HWND As Integer, ByRef lpRect As RECT) As Integer

    Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
        Dim rc As RECT
        GetWindowRect(MyBase.Handle, rc)
        Dim width As Integer = rc.Right - rc.Left
        Form2.Show()
        Form2.Location = New Point(rc.Right, rc.Top)
    End Sub

End Class

在此处输入图像描述

我要记住:这个问题只发生在win7/Vista上运行编译的应用程序时,而不是从IDE启动应用程序时

4

3 回答 3

2

我对 vb.net 没有太多经验,但通常我会使用 GetWindowRect() 来获取窗口的完整外边框。它似乎在 vb.net 中可用

http://www.pinvoke.net/default.aspx/user32/getwindowrect.html

现在我从 6.0 版开始就没有使用过 vb,但您可能必须将该矩形从像素转换为缇。

编辑:

这段代码对我有用:

Imports System.Runtime.InteropServices

Public Class Form1
    <StructLayout(LayoutKind.Sequential)> _
    Private Structure RECT
        Public Left As Int32
        Public Top As Int32
        Public Right As Int32
        Public Bottom As Int32
    End Structure

    Private Declare Function GetWindowRect Lib "user32" (ByVal HWND As Integer, ByRef lpRect As RECT) As Integer

    Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
        Dim rc As RECT
        GetWindowRect(MyBase.Handle.ToInt32, rc)

        Dim width As Integer = rc.Right - rc.Left
        MessageBox.Show(width.ToString)

    End Sub
End Class
于 2013-04-25T21:10:12.807 回答
2

虽然我没有亲自测试过,但您可以使用 DwmExtendFrameIntoClientArea 并传递 -1 将框架扩展到客户区域。

从理论上讲,这应该意味着您指定的尺寸/位置将包括框架。

C# 签名

[DllImport("dwmapi.dll", PreserveSig = true)]
static extern int DwmExtendFrameIntoClientArea(IntPtr hwnd, ref MARGINS margins);

[DllImport("dwmapi.dll", PreserveSig = false)]
static extern void DwmExtendFrameIntoClientArea(IntPtr hwnd, ref MARGINS margins);

VB.NET 签名:

<DllImport("dwmapi.dll")> _
Private Shared Function DwmExtendFrameIntoClientArea(ByVal hwnd As IntPtr, ByRef margins As MARGINS) As Integer
End Sub

更新

您是否考虑过将表单边框样式设置为无,然后使用按钮来控制关闭/最小化?还有其他选择也可能让你得到你想要的结果 -FixedSingleFixedToolWindow

边框样式

更新 2

我设法重新创建您的问题并使用以下代码解决它。调试时窗口位置偏斜,但运行编译后的 exe 时窗口位置正确。

Dim BorderWidth = (Me.Width - Me.ClientSize.Width)
Me.Location = New Point((Form1.Location.X + (Form1.Width + BorderWidth)), Form1.Location.Y)
于 2013-04-23T16:42:22.513 回答
0

最后,我做了这个片段,用于将辅助窗体停靠在主窗体的右侧,即使启用了 Aero 并且如果我们没有运行 APP fom 调试,现在我的应用程序可以停靠在虚拟机上启用 AERO 和所有(航空)Windows:D。

  ' Instructions :
  ' Change Manually the "StartPosition" property of "Form2" to "Manual", don't change it with code.

    Public Moving_From_Secondary_Form As Boolean = False

    ' Move Event Main Form
    Private Sub Form1_Move(ByVal sender As Object, ByVal e As System.EventArgs) Handles MyBase.Move
        If Not Moving_From_Secondary_Form Then
            If Debugger.IsAttached Then
                Form2.Location = New Point(Me.Right, Me.Top)
            Else
                Form2.Location = New Point((Me.Location.X + (Me.Width + (Me.Width - Me.ClientSize.Width))), Me.Location.Y)
            End If
        End If
    End Sub

    ' Move Event Secondary Form
    Private Sub Form2_Move(ByVal sender As Object, ByVal e As System.EventArgs) Handles MyBase.Move
        Form1.Moving_From_Secondary_Form = True
        If Debugger.IsAttached Then
            Form1.Location = New Point(Me.Left - Form1.Width, Me.Top)
        Else
            Form1.Location = New Point((Me.Location.X - (Form1.Width + (Form1.Width - Form1.ClientSize.Width))), Me.Location.Y)
        End If
        Form1.Moving_From_Secondary_Form = False
    End Sub

...还有这个功能:

#Region " Get Non-Client Area Width "

    ' [ Get Non-Client Area Width Function ]
    '
    ' Examples :
    ' MsgBox(Get_NonClientArea_Width(Form1))
    ' Me.Location = New Point((Form1.Location.X + (Form1.Width + Get_NonClientArea_Width(Form1))), Form1.Location.Y) 

    Public Function Get_NonClientArea_Width(ByVal Form Form) As Int32
        Return (Form.Width - Form.ClientSize.Width)
    End Function

#End Region
于 2013-04-27T00:42:36.040 回答