Как правильно определить размер не-клиентской области для 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
Другие вопросы по тегам