Как правильно определить размер не-клиентской области для Aero?
Как правильно определить с помощью кода VBNET или C# размер не-клиентской области, когда Aero активирован для скомпилированного приложения? (Да, эта проблема возникает только при запуске скомпилированного приложения, а не при запуске приложения из 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
Form2:
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
3 ответа
Хотя я не проверял это лично, вы можете расширить фрейм в клиентскую область, используя 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
Обновить
Задумывались ли вы о том, чтобы установить стиль границы форм на none, а затем использовать кнопку для управления закрытием / свертыванием? Есть и другие варианты, которые могут дать вам результат тоже после - FixedSingle
а также FixedToolWindow
ОБНОВЛЕНИЕ 2
Мне удалось воссоздать вашу проблему и решить ее с помощью следующего кода. При отладке положение окна перекошено, но при запуске скомпилированного exe расположение окна является правильным.
Dim BorderWidth = (Me.Width - Me.ClientSize.Width)
Me.Location = New Point((Form1.Location.X + (Form1.Width + BorderWidth)), Form1.Location.Y)
У меня нет особого опыта работы с vb.net, но обычно я использую GetWindowRect(), чтобы получить полную внешнюю границу окна. Похоже, что доступно в vb.net
http://www.pinvoke.net/default.aspx/user32/getwindowrect.html
Теперь я не использовал vb начиная с версии 6.0, но вам, возможно, придется конвертировать этот прямоугольник из пикселей в твипы.
Редактировать:
Этот код работает для меня:
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
Наконец, я сделал этот фрагмент для закрепления дополнительной формы справа от основной формы, которая работает, даже если Aero включен, и если мы не запускаем приложение APP для отладки, теперь мои приложения могут быть пристыкованы с включенным AERO на виртуальных машинах и все (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