Error404 Error404 - 3 months ago 15
Vb.net Question

Windows Default Context Menu on Borderless Windows Form replace not working Options with custom ones

I created an Borderless Windows Form and added the functionalities of the default System Header:

Moving:



Private m_blnMouseDown As Boolean = False
Private m_utdMouseOffset As Point

' Left mouse button pressed
Private Sub BorderlessMove_MouseDown(sender As Object, e As MouseEventArgs) Handles tlpHeader.MouseDown
If e.Button = MouseButtons.Left Then
' Get the new position
Dim mouseRelative As Point = Me.PointToClient(Cursor.Position)
m_utdMouseOffset = New Point(-mouseRelative.X, -mouseRelative.Y)
' Set that left button is pressed
m_blnMouseDown = True
End If
End Sub

' MouseMove used to check if mouse cursor is moving
Private Sub BorderlessMove_MouseMove(sender As Object, e As MouseEventArgs) Handles tlpHeader.MouseMove
If m_blnMouseDown Then
Dim mousePos As Point = Control.MousePosition
' Get the new form position
mousePos.Offset(m_utdMouseOffset.X, m_utdMouseOffset.Y)
Me.Location = mousePos
End If
End Sub

' Left mouse button released, form should stop moving
Private Sub BorderlessMove_MouseUp(sender As Object, e As MouseEventArgs) Handles tlpHeader.MouseUp
If e.Button = MouseButtons.Left Then
m_blnMouseDown = False
End If
End Sub


Resizing:



Private Enum ResizeState
North
NE
East
SE
South
SW
West
NW
None
End Enum

Private m_utdResizeState As ResizeState = ResizeState.None

Private Const GRIP_SIZE As Int32 = 5

Private Sub BorderlessResize_FormLoad(sender As Object, e As EventArgs) Handles Me.Load

Const DGRIP_SIZE As Int32 = GRIP_SIZE * 2

Dim Sizes As New Dictionary(Of String, Size)
Sizes.Add("Horizontal", New Size(Me.Width - DGRIP_SIZE * 2, GRIP_SIZE))
Sizes.Add("Vertical", New Size(GRIP_SIZE, Me.Height - DGRIP_SIZE * 2))
Sizes.Add("HEdge", New Size(DGRIP_SIZE, GRIP_SIZE))
Sizes.Add("VEdge", New Size(GRIP_SIZE, DGRIP_SIZE))

GenerateTransparentPanel("pnlResizeNorth", ResizeState.North, Sizes.Item("Horizontal"), New Point(DGRIP_SIZE, 0), (AnchorStyles.Top Or AnchorStyles.Right) Or AnchorStyles.Left)
GenerateTransparentPanel("pnlResizeNE_H", ResizeState.NE, Sizes.Item("HEdge"), New Point(Me.Width - DGRIP_SIZE, 0), AnchorStyles.Top Or AnchorStyles.Right)
GenerateTransparentPanel("pnlResizeNE_V", ResizeState.NE, Sizes.Item("VEdge"), New Point(Me.Width - GRIP_SIZE, 0), AnchorStyles.Top Or AnchorStyles.Right)
GenerateTransparentPanel("pnlResizeEast", ResizeState.East, Sizes.Item("Vertical"), New Point(Me.Width - GRIP_SIZE, DGRIP_SIZE), (AnchorStyles.Top Or AnchorStyles.Right) Or AnchorStyles.Bottom)
GenerateTransparentPanel("pnlResizeSE_H", ResizeState.SE, Sizes.Item("HEdge"), New Point(Me.Width - DGRIP_SIZE, Me.Height - GRIP_SIZE), AnchorStyles.Right Or AnchorStyles.Bottom)
GenerateTransparentPanel("pnlResizeSE_V", ResizeState.SE, Sizes.Item("VEdge"), New Point(Me.Width - GRIP_SIZE, Me.Height - DGRIP_SIZE), AnchorStyles.Right Or AnchorStyles.Bottom)
GenerateTransparentPanel("pnlResizeSouth", ResizeState.South, Sizes.Item("Horizontal"), New Point(DGRIP_SIZE, Me.Height - GRIP_SIZE), (AnchorStyles.Bottom Or AnchorStyles.Right) Or AnchorStyles.Left)
GenerateTransparentPanel("pnlResizeSW_H", ResizeState.SW, Sizes.Item("HEdge"), New Point(0, Me.Height - GRIP_SIZE), AnchorStyles.Bottom Or AnchorStyles.Left)
GenerateTransparentPanel("pnlResizeSW_V", ResizeState.SW, Sizes.Item("VEdge"), New Point(0, Me.Height - DGRIP_SIZE), AnchorStyles.Bottom Or AnchorStyles.Left)
GenerateTransparentPanel("pnlResizeWest", ResizeState.West, Sizes.Item("Vertical"), New Point(0, DGRIP_SIZE), (AnchorStyles.Top Or AnchorStyles.Left) Or AnchorStyles.Bottom)
GenerateTransparentPanel("pnlResizeNW_H", ResizeState.NW, Sizes.Item("HEdge"), New Point(0, 0), AnchorStyles.Top Or AnchorStyles.Left)
GenerateTransparentPanel("pnlResizeNW_V", ResizeState.NW, Sizes.Item("VEdge"), New Point(0, 0), AnchorStyles.Top Or AnchorStyles.Left)

End Sub

Private Sub GenerateTransparentPanel(name As String, tag As ResizeState, size As Size, location As Point, anchors As AnchorStyles)
Dim panel As TransparentPanel = New TransparentPanel()
panel.Anchor = anchors
panel.Location = location
panel.Name = name
panel.Size = size
panel.Tag = tag
AddHandler panel.MouseDown, AddressOf BorderlessResize_MouseDown
AddHandler panel.MouseMove, AddressOf BorderlessResize_MouseMove
AddHandler panel.MouseUp, AddressOf BorderlessResize_MouseUp
AddHandler panel.MouseEnter, AddressOf BorderlessResize_MouseEnter
AddHandler panel.MouseLeave, AddressOf BorderlessResize_MouseLeave
Me.Controls.Add(panel)
panel.BringToFront()
End Sub

Private Sub BorderlessResize_MouseDown(sender As Object, e As MouseEventArgs)
Debug.Write("MouseDown")
If e.Button = MouseButtons.Left Then
m_utdResizeState = DirectCast(sender, Control).Tag
End If
End Sub

Protected Sub BorderlessResize_MouseMove(sender As Object, e As MouseEventArgs)
If m_utdResizeState <> ResizeState.None Then
BorderlessResize_ResizeForm(m_utdResizeState)
Refresh()
End If
End Sub
Protected Sub BorderlessResize_MouseEnter(sender As Object, e As EventArgs)
BorderlessResize_UpdateCursor(DirectCast(sender, Control).Tag)
End Sub
Protected Sub BorderlessResize_MouseLeave(sender As Object, e As EventArgs)
Me.Cursor = Cursors.Default
End Sub

Private Sub BorderlessResize_UpdateCursor(state As ResizeState)
If (state = ResizeState.East OrElse state = ResizeState.West) Then
Me.Cursor = Cursors.SizeWE
ElseIf (state = ResizeState.North OrElse state = ResizeState.South) Then
Me.Cursor = Cursors.SizeNS
ElseIf (state = ResizeState.SE OrElse state = ResizeState.NW) Then
Me.Cursor = Cursors.SizeNWSE
ElseIf (state = ResizeState.NE OrElse state = ResizeState.SW) Then
Me.Cursor = Cursors.SizeNESW
Else Me.Cursor = Cursors.Default
End If
End Sub

Private Sub BorderlessResize_ResizeForm(ResizeVal As ResizeState)
Dim Location As Point = New Point(Cursor.Position.X - Me.Left, Cursor.Position.Y - Me.Top)
Select Case ResizeVal
Case ResizeState.North
If Me.Height - Location.Y <= Me.MinimumSize.Height Then Return
Me.Height = Me.Height - Location.Y
Me.Top = Me.Top + Location.Y
Exit Select
Case ResizeState.South
Me.Height = Location.Y
Exit Select
Case ResizeState.East
Me.Width = Location.X
Exit Select
Case ResizeState.West
If Me.Width - Location.X <= Me.MinimumSize.Width Then Return
Me.Width = Me.Width - Location.X
Me.Left = Me.Left + Location.X
Exit Select
Case ResizeState.NE
BorderlessResize_ResizeForm(ResizeState.North)
BorderlessResize_ResizeForm(ResizeState.East)
Exit Select
Case ResizeState.SE
BorderlessResize_ResizeForm(ResizeState.South)
BorderlessResize_ResizeForm(ResizeState.East)
Exit Select
Case ResizeState.SW
BorderlessResize_ResizeForm(ResizeState.South)
BorderlessResize_ResizeForm(ResizeState.West)
Exit Select
Case ResizeState.NW
BorderlessResize_ResizeForm(ResizeState.North)
BorderlessResize_ResizeForm(ResizeState.West)
Exit Select
End Select
End Sub

Protected Sub BorderlessResize_MouseUp(sender As Object, e As MouseEventArgs)
If e.Button = MouseButtons.Left Then
m_utdResizeState = ResizeState.None
End If
End Sub


Default Context Menu



Private Const WS_SYSMENU As Integer = &H80000
Private Const WS_MINIMIZEBOX As Integer = &H20000
Private Const WS_MAXIMIZEBOX As Integer = &H10000
Protected Overrides ReadOnly Property CreateParams As System.Windows.Forms.CreateParams
Get
Dim p = MyBase.CreateParams
p.Style = WS_SYSMENU + WS_MINIMIZEBOX + WS_MAXIMIZEBOX
Return p
End Get
End Property

<DllImport("user32.dll")>
Private Shared Function SendMessage(ByVal hWnd As IntPtr, ByVal msg As Integer,
ByVal wParam As IntPtr, ByVal lParam As IntPtr) As IntPtr
End Function
Private Const WM_POPUPSYSTEMMENU = &H313
Protected Overrides Sub OnMouseDown(ByVal e As System.Windows.Forms.MouseEventArgs)
MyBase.OnMouseDown(e)
Dim p = MousePosition.X + (MousePosition.Y * &H10000)
SendMessage(Me.Handle, WM_POPUPSYSTEMMENU, 0, p)
End Sub


Moving and Resizing works just fine, but my Context Menu is always displayed in the top left corner and
MOVE
and
SIZE
Options are not working because they need the Default Window Frame which I removed.

So is there a possibility to implement my solutions for Moving and Resizing into the Context Menu?

Is

Answer

SOLUTION 1

with WndPrc Overwrite

Private Sub Header_MouseDown(sender As Object, ByVal e As MouseEventArgs)
    If e.Button = MouseButtons.Right Then
      Dim p As IntPtr = ((MousePosition.Y * WindowStyles.WS_MAXIMIZEBOX) + (MousePosition.X And &HFFFF))
      Dim test As IntPtr = SendMessage(Me.Handle, WindowMessages.WM_POPUPSYSMENU, 0, p)
    End If
  End Sub

Protected Overrides Sub WndProc(ByRef m As Message)
    If (m.Msg = WindowMessages.WM_SYSCOMMAND)
        'Do SOmething with m.wParam
    Else
      MyBase.WndProc(m)
    End If
  End Sub

SOLUTION 2

with TrackMenuBar

Private Sub Header_MouseDown(sender As Object, ByVal e As MouseEventArgs)
    If e.Button = MouseButtons.Right Then'Alternate Solution

    Dim sysMenu As IntPtr = GetSystemMenu(Me.Handle, False)
    Dim cmd As IntPtr = TrackPopupMenu(
               sysMenu,
               TrackPopupMenuOptions.TOPALIGN Or
               TrackPopupMenuOptions.NOANIMATION Or
               TrackPopupMenuOptions.RETURNCMD Or
               TrackPopupMenuOptions.LEFTALIGN Or
               TrackPopupMenuOptions.RIGHTBUTTON,
               MousePosition.X,
               MousePosition.Y,
               IntPtr.Zero,
               Me.Handle,
               IntPtr.Zero)
    'Do Something with cmd
    End If
End Sub
Comments