如何为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被激活,那就是结果:
注意权利的形式如何在左表格的非客户边界下。
...或者这是其他图像,其中左表单位于右表单的非客户端边框下:
我的问题是解决此问题的方法是什么?
更新
扩展框架解决方案无效。
Form1中:
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
结果:
http://img824.imageshack.us/img824/3176/prtscrcapture2q.jpg
我还想记住: 此问题仅在运行已编译的应用程序时发生,而不是在从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启动应用程序时
答案 0 :(得分: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
<强>更新强>
您是否考虑过将表格边框样式设置为无,然后使用按钮来控制关闭/最小化?还有其他选项可以帮助您获得结果 - FixedSingle
和FixedToolWindow
更新2
我设法重新创建您的问题并使用以下代码解决它。调试时,窗口位置是倾斜的,但在运行编译的exe时,窗口位置是正确的。
Dim BorderWidth = (Me.Width - Me.ClientSize.Width)
Me.Location = New Point((Form1.Location.X + (Form1.Width + BorderWidth)), Form1.Location.Y)
答案 1 :(得分: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
答案 2 :(得分:0)
最后,我做了这个Snippet for Docking一个辅助表单到主表单的右边,即使启用了Aero,如果我们没有运行APP fom调试, 现在我的应用程序可以在虚拟机和所有(AERO)Windows上启用AERO停靠: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