-2

I have a winforms application and at times the main thread is extremely busy. When the main thread is busy, I want the user to be able to drag and drop the main form (using the pbAppHeader control at the top of the form), so they can reposition the main form on the screen. Since the main thread is extremely busy at times, moving the main form is very slow and jerky.

How do I run the following subs on a different thread or backgroundworker so moving the main form is smooth? Or is there a better way to do this?

Dim drag As Boolean
Dim mousex As Integer
Dim mousey As Integer

Private Sub pbAppHeader_MouseDown(ByVal sender As Object, ByVal e As System.Windows.Forms.MouseEventArgs) Handles pbAppHeader.MouseDown
    drag = True 'Sets the variable drag to true.
    mousex = Windows.Forms.Cursor.Position.X - Me.Left 'Sets variable mousex
    mousey = Windows.Forms.Cursor.Position.Y - Me.Top 'Sets variable mousey
End Sub

Private Sub pbAppHeader_MouseMove(ByVal sender As Object, ByVal e As System.Windows.Forms.MouseEventArgs) Handles pbAppHeader.MouseMove
    'If drag is set to true then move the form accordingly.
    If drag Then
        Me.Top = Windows.Forms.Cursor.Position.Y - mousey
        Me.Left = Windows.Forms.Cursor.Position.X - mousex
    End If
End Sub

Private Sub pbAppHeader_MouseUp(ByVal sender As Object, ByVal e As System.Windows.Forms.MouseEventArgs) Handles pbAppHeader.MouseUp
    drag = False 'Sets drag to false, so the form does not move according to the code in MouseMove
End Sub
Dan
  • 39
  • 7
  • 4
    You are going about it backwards: do the long running intensive task on the Background worker to leave the UI thread responsive – Ňɏssa Pøngjǣrdenlarp Feb 06 '16 at 23:03
  • Yeah, that was my first thought, but the thing is that this app only does one task... and it is either doing that one task or it is completely idle. So I could move EVERYTHING to another thread (which would be extremely complicated), or find a way to move the above subs to another thread. – Dan Feb 06 '16 at 23:09
  • You absolutely *cannot* just go about it the wrong way. There is only one UI thread, and all UI events must run on that thread. You cannot do UI on a background thread. And locking up your *main UI* thread while you're running some computationally-intensive task is a horrible idea, even if you find some way to hack around it (as you apparently have). The operating system will decide that your application has become unresponsive because it is not responding to UI messages. A redesign is sorely needed here. Do as Plutonix suggested and move the long-running task to a BackgroundWorker. – Cody Gray - on strike Feb 07 '16 at 15:50
  • First of all, the fix I found is not a hack at all... it is the correct way to move a borderless form, as well documented by the 93 up votes in this thread: http://stackoverflow.com/questions/1592876/make-a-borderless-form-movable/1592899#1592899. Secondly, ALL of the events are UI events, so I am assuming that you would suggest that they ALL MUST run on the UI thread, right? If you would rather down vote than help find the solution, that's cool with me, it seriously cracks me up... every question I ask gets a down vote and no solution... but I always find the correct answer in the end. – Dan Feb 08 '16 at 01:16
  • I didn't downvote, so your anger/amusement is misdirected. The point of asking a question here is to get good advice from experts. Someone tried to make the point already, but didn't provide much evidence. That made it possible to ignore it, as is our first instinct when trying to solve a problem. We just want to fix it, we don't want to hear that we're doing it the wrong way. So when we find something that seems to work, we latch onto it and bear forward. The purpose of my comment was to reiterate and explain, both to you and future viewers of this question, that it's still the wrong approach – Cody Gray - on strike Feb 08 '16 at 09:54
  • Yes, Joey has explained how to make a borderless form movable. That is in fact how you do it. All that Joey's code (and yours) is doing is telling the window manager that the user has indeed clicked on a form's caption/title, and therefore it should respond like it normally would when they click on the border. In your case, that should be unnecessary—a form with borders is *already* movable. And yes, doing UI on background threads is not a workable solution. However, the BackgroundWorker class is designed to help simulate it using callbacks that invoke updates of UI from background threads. – Cody Gray - on strike Feb 08 '16 at 09:57

1 Answers1

0

In case anyone runs into a similar situation, this works very well.

Public Const WM_NCLBUTTONDOWN As Integer = &HA1
Public Const HT_CAPTION As Integer = &H2

Private Sub pbAppHeader_MouseDown(ByVal sender As Object, ByVal e As System.Windows.Forms.MouseEventArgs) Handles pbAppHeader.MouseDown
    If e.Button = MouseButtons.Left Then
        NativeMethods.ReleaseCapture()
        NativeMethods.SendMessage(Handle, WM_NCLBUTTONDOWN, HT_CAPTION, 0)
    End If
End Sub

<ComVisible(True)> Friend Class NativeMethods

    <DllImport("user32.dll", SetLastError:=True, CharSet:=CharSet.Auto)> _
    Public Shared Function SendMessage(ByVal hWnd As IntPtr, ByVal Msg As UInteger, ByVal wParam As IntPtr, ByVal lParam As IntPtr) As IntPtr
    End Function

    <DllImportAttribute("user32.dll")> _
    Public Shared Function ReleaseCapture() As Boolean
    End Function

End Class
Dan
  • 39
  • 7