문제

I'm trying to write a code which locks the position of a form.

I've added a boolean property, when True then the form position would be locked, when False the form should return to normal state.

public class blahblah blah
    Inherits NativeWindow
    Implements IDisposable

Public Property LockPosition As Boolean = False

Private WithEvents form As Form = Nothing

Public Sub New(ByVal form As Form)
    Me.form = form
End Sub

Private Sub OnHandleCreated() _
Handles form.HandleCreated

    Me.AssignHandle(Me.form.Handle)

End Sub

Private Sub OnHandleDestroyed() _
Handles form.HandleDestroyed

    Me.ReleaseHandle()

End Sub

Protected Overrides Sub WndProc(ByRef m As Message)

    If Me.LockPosition Then

        Select Case m.Msg

            Case &HA1
                ' Cancels any attempt to drag the window by it's caption.
                If m.WParam.ToInt32 = &H2 Then Return

            Case &H112
                ' Cancels any clicks on the Move system menu item.
                If (m.WParam.ToInt32 And &HFFF0) = &HF010& Then Return

        End Select

    End If

    ' Return control to base message handler.
    MyBase.WndProc(m)

End Sub

Private disposedValue As Boolean ' To detect redundant calls

' IDisposable
Protected Overridable Sub Dispose(disposing As Boolean)
    If Not Me.disposedValue Then
        If disposing Then


            Me.LockPosition = False


        End If
    End If
    Me.disposedValue = True
End Sub

Public Sub Dispose() Implements IDisposable.Dispose
    Dispose(True)
    GC.SuppressFinalize(Me)
End Sub

end class

The code above is working when I instance the class for first time, the problem occurs when I dispose the class and I instance it again for a new Form, I don't know if the problem is the property, the assigned handle, or the windows messages, but when I try to set the LockPosition property to True for another form it does not lock nothing, this is how I'm using it:

EDIT:

I've discovered that does not matter the form passed at the New constructor, the problem is it only works if the object is instanced outside any procedure!

...So this will work, the form will be locked:

Public Class Form1

    Private _formdock As New FormDock(Me) With {.LockPosition = True}

    Private Shadows Sub Shown() Handles MyBase.Shown
        _formdock.Dock(FormDock.DockPosition.WorkingArea_BottomRight)
    End Sub

End Class

...But this else does not work, the form is not locked anymore!

Public Class Form1

    Private Shadows Sub Shown() Handles MyBase.Shown
        Dim _formdock As New FormDock(Me) With {.LockPosition = True}
        _formdock.Dock(FormDock.DockPosition.WorkingArea_BottomRight)
    End Sub

End Class

Then why happens that and How I could fix it?


Here is the Full Class:

' [ Form Dock ]
'
' // By Elektro H@cker

#Region " Usage Examples "

' Dim _formdock As New FormDock(Me) With {.LockPosition = True}
'
' Private Shadows Sub shown() Handles MyBase.Shown
'
'    _formdock.Dock(FormDock.DockPosition.WorkingArea_BottomRight)
'
' End Sub

#End Region

#Region " Form Dock "

Public Class FormDock
    Inherits NativeWindow
    Implements IDisposable

#Region " Variables, Properties and Enumerations "

    ''' <summary>
    ''' While the property still Enabled it will locks the formulary position.
    ''' </summary>
    Public Property LockPosition As Boolean = False

    ''' <summary>
    ''' Stores the formulary to Dock.
    ''' </summary>
    Private WithEvents form As Form = Nothing

    ''' <summary>
    ''' Stores the size of the formulary to Dock.
    ''' </summary>
    Private UI_Size As Size = Nothing

    ''' <summary>
    ''' Stores the Dock positions.
    ''' </summary>
    Private Dock_Positions As Dictionary(Of DockPosition, Point)

    ''' <summary>
    ''' Dock Positions.
    ''' </summary>
    Public Enum DockPosition As Short
        Bounds_BottomLeft = 1
        Bounds_BottomRight = 2
        Bounds_TopLeft = 3
        Bounds_TopRight = 4
        WorkingArea_BottomLeft = 5
        WorkingArea_BottomRight = 6
        WorkingArea_TopLeft = 7
        WorkingArea_TopRight = 8
    End Enum

#End Region

#Region " New Constructor "

    Public Sub New(ByVal form As Form)

        Me.form = form

    End Sub

#End Region

#Region " Public Procedures "

    ''' <summary>
    ''' Docks the form.
    ''' </summary>
    Public Sub Dock(ByVal Position As DockPosition)

        If Dock_Positions Is Nothing Then
            Renew_Positions(form)
        End If

        form.Location = Dock_Positions(Position)

    End Sub

#End Region

#Region " Miscellaneous Procedures "

    ''' <summary>
    ''' Renews the Dock positions according to the the current form Size.
    ''' </summary>
    Private Sub Renew_Positions(ByVal form As Form)

        UI_Size = form.Size

        Dock_Positions = New Dictionary(Of DockPosition, Point) _
        From {
                 {DockPosition.Bounds_BottomLeft,
                               New Point(Screen.PrimaryScreen.Bounds.X,
                                         Screen.PrimaryScreen.Bounds.Height - UI_Size.Height)},
                 {DockPosition.Bounds_BottomRight,
                           New Point(Screen.PrimaryScreen.Bounds.Width - UI_Size.Width,
                                     Screen.PrimaryScreen.Bounds.Height - UI_Size.Height)},
                 {DockPosition.Bounds_TopLeft,
                               New Point(Screen.PrimaryScreen.Bounds.X,
                                         Screen.PrimaryScreen.Bounds.Y)},
                 {DockPosition.Bounds_TopRight,
                               New Point(Screen.PrimaryScreen.Bounds.Width - UI_Size.Width,
                                         Screen.PrimaryScreen.Bounds.Y)},
                 {DockPosition.WorkingArea_BottomLeft,
                               New Point(Screen.PrimaryScreen.WorkingArea.X,
                                         Screen.PrimaryScreen.WorkingArea.Height - UI_Size.Height)},
                 {DockPosition.WorkingArea_BottomRight,
                               New Point(Screen.PrimaryScreen.WorkingArea.Width - UI_Size.Width,
                                         Screen.PrimaryScreen.WorkingArea.Height - UI_Size.Height)},
                 {DockPosition.WorkingArea_TopLeft,
                               New Point(Screen.PrimaryScreen.WorkingArea.X,
                                         Screen.PrimaryScreen.WorkingArea.Y)},
                 {DockPosition.WorkingArea_TopRight,
                               New Point(Screen.PrimaryScreen.WorkingArea.Width - UI_Size.Width,
                                         Screen.PrimaryScreen.WorkingArea.Y)}
            }

    End Sub

#End Region

#Region " Form EventHandlers "

    ''' <summary>
    ''' Renews the Dock positions according to the the current form Size,
    ''' when Form is Shown.
    ''' </summary>
    Private Sub OnShown() _
    Handles form.Shown

        If Not UI_Size.Equals(Me.form.Size) Then
            Renew_Positions(Me.form)
        End If

    End Sub

    ''' <summary>
    ''' Renews the Dock positions according to the the current form Size,
    ''' When Form is resized.
    ''' </summary>
    Private Sub OnResizeEnd() _
    Handles form.ResizeEnd

        If Not UI_Size.Equals(Me.form.Size) Then
            Renew_Positions(Me.form)
        End If

    End Sub

    ''' <summary>
    ''' OnHandleCreated
    ''' Assign the handle of this NativeWindow to the form handle,
    ''' necessary to override WndProc.
    ''' </summary>
    Private Sub OnHandleCreated() _
    Handles form.HandleCreated

        Me.AssignHandle(Me.form.Handle)

    End Sub

    ''' <summary>
    ''' Releases the Handle.
    ''' </summary>
    Private Sub OnHandleDestroyed() _
    Handles form.HandleDestroyed

        Me.ReleaseHandle()

    End Sub

#End Region

#Region " Windows Messages "

    ''' <summary>
    ''' WndProc Message Interception.
    ''' </summary>
    Protected Overrides Sub WndProc(ByRef m As Message)

        If Me.LockPosition Then

            Select Case m.Msg

                Case &HA1
                    ' Cancels any attempt to drag the window by it's caption.
                    If m.WParam.ToInt32 = &H2 Then Return

                Case &H112
                    ' Cancels any clicks on the Move system menu item.
                    If (m.WParam.ToInt32 And &HFFF0) = &HF010& Then Return

            End Select

        End If

        ' Return control to base message handler.
        MyBase.WndProc(m)

    End Sub

#End Region

#Region "IDisposable Support"

    Private disposedValue As Boolean ' To detect redundant calls

    ' IDisposable
    Protected Overridable Sub Dispose(disposing As Boolean)
        If Not Me.disposedValue Then
            If disposing Then
                Me.LockPosition = False
            End If

            ' TODO: free unmanaged resources (unmanaged objects) and override Finalize() below.
            ' TODO: set large fields to null.
        End If
        Me.disposedValue = True
    End Sub

    Public Sub Dispose() Implements IDisposable.Dispose
        Dispose(True)
        GC.SuppressFinalize(Me)
    End Sub

#End Region

End Class

#End Region
도움이 되었습니까?

해결책

The working code:

' [ Form Docking ]
'
' // By Elektro H@cker

#Region " Usage Examples "

' Private _FormDocking As New FormDocking(Me) With {.LockPosition = True}
'
' Private Shadows Sub Shown() Handles MyBase.Shown
'
'   _FormDocking.Dock(FormDocking.DockPosition.WorkingArea_BottomRight)
'
' End Sub

#End Region

#Region " Form Docking "

Public Class FormDocking
    Inherits NativeWindow
    Implements IDisposable

#Region " Variables, Properties and Enumerations "

    ''' <summary>
    ''' While the property still Enabled it will locks the formulary position.
    ''' </summary>
    Public Property LockPosition As Boolean = False

    ''' <summary>
    ''' Stores the formulary to Dock.
    ''' </summary>
    Private WithEvents form As Form = Nothing

    ''' <summary>
    ''' Stores the size of the formulary to Dock.
    ''' </summary>
    Private UI_Size As Size = Nothing

    ''' <summary>
    ''' Stores the Dock positions.
    ''' </summary>
    Private Positions As Dictionary(Of DockPosition, Point)

    ''' <summary>
    ''' Dock Positions.
    ''' </summary>
    Public Enum DockPosition As Short
        Center_Screen = 0
        Bounds_BottomLeft = 1
        Bounds_BottomRight = 2
        Bounds_TopLeft = 3
        Bounds_TopRight = 4
        WorkingArea_BottomLeft = 5
        WorkingArea_BottomRight = 6
        WorkingArea_TopLeft = 7
        WorkingArea_TopRight = 8
    End Enum

#End Region

#Region " Constructor "

    Public Sub New(ByVal form As Form)

        Me.form = form
        SetHandle()

    End Sub

#End Region

#Region " Public Methods "

    ''' <summary>
    ''' Docks the form.
    ''' </summary>
    Public Sub Dock(ByVal Position As DockPosition)

        DisposedCheck()

        If Positions Is Nothing Then
            Renew_Positions(form)
        End If

        form.Location = Positions(Position)

    End Sub

#End Region

#Region " Miscellaneous Methods "

    ''' <summary>
    ''' Renews the Dock positions according to the the current form Size.
    ''' </summary>
    Private Sub Renew_Positions(ByVal form As Form)

        UI_Size = form.Size

        Positions = New Dictionary(Of DockPosition, Point) _
        From {
                 {DockPosition.Center_Screen,
                               New Point((Screen.PrimaryScreen.Bounds.Width - UI_Size.Width) \ 2,
                                         (Screen.PrimaryScreen.Bounds.Height - UI_Size.Height) \ 2)},
                 {DockPosition.Bounds_BottomLeft,
                               New Point(Screen.PrimaryScreen.Bounds.X,
                                         Screen.PrimaryScreen.Bounds.Height - UI_Size.Height)},
                 {DockPosition.Bounds_BottomRight,
                           New Point(Screen.PrimaryScreen.Bounds.Width - UI_Size.Width,
                                     Screen.PrimaryScreen.Bounds.Height - UI_Size.Height)},
                 {DockPosition.Bounds_TopLeft,
                               New Point(Screen.PrimaryScreen.Bounds.X,
                                         Screen.PrimaryScreen.Bounds.Y)},
                 {DockPosition.Bounds_TopRight,
                               New Point(Screen.PrimaryScreen.Bounds.Width - UI_Size.Width,
                                         Screen.PrimaryScreen.Bounds.Y)},
                 {DockPosition.WorkingArea_BottomLeft,
                               New Point(Screen.PrimaryScreen.WorkingArea.X,
                                         Screen.PrimaryScreen.WorkingArea.Height - UI_Size.Height)},
                 {DockPosition.WorkingArea_BottomRight,
                               New Point(Screen.PrimaryScreen.WorkingArea.Width - UI_Size.Width,
                                         Screen.PrimaryScreen.WorkingArea.Height - UI_Size.Height)},
                 {DockPosition.WorkingArea_TopLeft,
                               New Point(Screen.PrimaryScreen.WorkingArea.X,
                                         Screen.PrimaryScreen.WorkingArea.Y)},
                 {DockPosition.WorkingArea_TopRight,
                               New Point(Screen.PrimaryScreen.WorkingArea.Width - UI_Size.Width,
                                         Screen.PrimaryScreen.WorkingArea.Y)}
            }

    End Sub

#End Region

#Region " Event Handlers "

    ''' <summary>
    ''' Renews the Dock positions according to the the current form Size,
    ''' when Form is Shown.
    ''' </summary>
    Private Sub OnShown() _
    Handles form.Shown

        If Not UI_Size.Equals(Me.form.Size) Then
            Renew_Positions(Me.form)
        End If

    End Sub

    ''' <summary>
    ''' Renews the Dock positions according to the the current form Size,
    ''' When Form is resized.
    ''' </summary>
    Private Sub OnResizeEnd() _
    Handles form.ResizeEnd

        If Not UI_Size.Equals(Me.form.Size) Then
            Renew_Positions(Me.form)
        End If

    End Sub

    ''' <summary>
    ''' SetHandle
    ''' Assign the handle of the target form to this NativeWindow,
    ''' necessary to override WndProc.
    ''' </summary>
    Private Sub SetHandle() Handles _
        form.HandleCreated,
        form.Load,
        form.Shown

        Try
            If Not Me.Handle.Equals(Me.form.Handle) Then
                Me.AssignHandle(Me.form.Handle)
            End If
        Catch ex As InvalidOperationException
        End Try

    End Sub

    ''' <summary>
    ''' Releases the Handle.
    ''' </summary>
    Private Sub OnHandleDestroyed() _
    Handles form.HandleDestroyed

        Me.ReleaseHandle()

    End Sub

#End Region

#Region " Windows Messages "

    ''' <summary>
    ''' WndProc Message Interception.
    ''' </summary>
    Protected Overrides Sub WndProc(ByRef m As Message)

        If Me.LockPosition Then

            Select Case m.Msg

                Case &HA1
                    ' Cancels any attempt to drag the window by it's caption.
                    If m.WParam.ToInt32 = &H2 Then Return

                Case &H112
                    ' Cancels any clicks on the Move system menu item.
                    If (m.WParam.ToInt32 And &HFFF0) = &HF010& Then Return

            End Select

        End If

        ' Return control to base message handler.
        MyBase.WndProc(m)

    End Sub

#End Region

#Region " IDisposable "

    ''' <summary>
    ''' To detect redundant calls when disposing.
    ''' </summary>
    Private IsDisposed As Boolean = False

    ''' <summary>
    ''' Prevents calls to methods after disposing.
    ''' </summary>
    Private Sub DisposedCheck()
        If Me.IsDisposed Then
            Throw New ObjectDisposedException(Me.GetType().FullName)
        End If
    End Sub

    ''' <summary>
    ''' Disposes the objects generated by this instance.
    ''' </summary>
    Public Sub Dispose() Implements IDisposable.Dispose
        Dispose(True)
        GC.SuppressFinalize(Me)
    End Sub

    ' IDisposable
    Protected Overridable Sub Dispose(IsDisposing As Boolean)

        If Not Me.IsDisposed Then

            If IsDisposing Then
            Me.LockPosition = False
            Me.form = Nothing
            Me.ReleaseHandle()
            Me.DestroyHandle()
            End If

        End If

        Me.IsDisposed = True

    End Sub

#End Region

End Class

#End Region
라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top