# VBForums CodeBank > CodeBank - Visual Basic .NET >  Move and Resize a Control or a Borderless Form - using window messages (smooth!)

## NickThissen

Hi,

Here is a small example of how to move and resize a form without a border (FormBorderStyle = None).

Instead of manually setting the Location and Size of the Form, I have decided to use the SendMessage function to handle it. This results in a much smoother experience, (especially with lots of controls) and will also make sure that the form always follows the mouse, regardless of how fast you move it. In other examples you will often notice that if you move your mouse too fast, the form can no longer keep up and will stop moving. 


The example uses a Panel as the form's caption. Dragging the panel will move the form, just like the real caption of a form with a border would behave.
You can of course decide to use a different control. You could even use the form itself. I just thought a Panel was the easiest example.

For resizing, I did not use any special controls; I merely use a BorderWith constant (default: 6) that defines the width of the area you can use to resize the form.

Screenshot:

(You can of course use nice icons for the buttons instead, but that was not the purpose of this codebank submission)



The form moving works pretty simple: when the MouseDown event of the Panel is fired, a simple check is done to make sure that the user clicked the Left button instead of the Right button, and that the form is not maximized (you cannot move a maximized form). 
Then, a MoveForm() method is called, in which the SendMessage function is called with the correct parameters.

vb.net Code:
Private Sub pnlCaption_MouseDown(ByVal sender As System.Object, ByVal e As System.Windows.Forms.MouseEventArgs) Handles pnlCaption.MouseDown
        If e.Button = Windows.Forms.MouseButtons.Left And Me.WindowState <> FormWindowState.Maximized Then
            MoveForm()
        End If
    End Sub
     Private Sub MoveForm()
        ReleaseCapture()
        SendMessage(Me.Handle, WM_NCLBUTTONDOWN, HTCAPTION, 0)
    End Sub


The resizing is a little more involved, as it requires a check for the position of the mouse cursor, and changes the cursor to a resizing cursor. 
For this, I made a Property *resizeDir* which changes the cursor depending on which value it gets automatically. 
The value of this property is used in a ResizeForm method, which calls the SendMessage function again with the correct parameters (depending on the position of the mouse, or the resizeDir value).

vb.net Code:
Private Sub Form1_MouseDown(ByVal sender As System.Object, ByVal e As System.Windows.Forms.MouseEventArgs) Handles MyBase.MouseDown
        If e.Button = Windows.Forms.MouseButtons.Left And Me.WindowState <> FormWindowState.Maximized Then
            ResizeForm(resizeDir)
        End If
    End Sub
     Private Sub Form1_MouseMove(ByVal sender As System.Object, ByVal e As System.Windows.Forms.MouseEventArgs) Handles MyBase.MouseMove
        'Calculate which direction to resize based on mouse position
         If e.Location.X < BorderWidth And e.Location.Y < BorderWidth Then
            resizeDir = ResizeDirection.TopLeft
         ElseIf e.Location.X < BorderWidth And e.Location.Y > Me.Height - BorderWidth Then
            resizeDir = ResizeDirection.BottomLeft
         ElseIf e.Location.X > Me.Width - BorderWidth And e.Location.Y > Me.Height - BorderWidth Then
            resizeDir = ResizeDirection.BottomRight
         ElseIf e.Location.X > Me.Width - BorderWidth And e.Location.Y < BorderWidth Then
            resizeDir = ResizeDirection.TopRight
         ElseIf e.Location.X < BorderWidth Then
            resizeDir = ResizeDirection.Left
         ElseIf e.Location.X > Me.Width - BorderWidth Then
            resizeDir = ResizeDirection.Right
         ElseIf e.Location.Y < BorderWidth Then
            resizeDir = ResizeDirection.Top
         ElseIf e.Location.Y > Me.Height - BorderWidth Then
            resizeDir = ResizeDirection.Bottom
         Else
            resizeDir = ResizeDirection.None
        End If
    End Sub
 Private Sub ResizeForm(ByVal direction As ResizeDirection)
        Dim dir As Integer = -1
        Select Case direction
            Case ResizeDirection.Left
                dir = HTLEFT
            Case ResizeDirection.TopLeft
                dir = HTTOPLEFT
            Case ResizeDirection.Top
                dir = HTTOP
            Case ResizeDirection.TopRight
                dir = HTTOPRIGHT
            Case ResizeDirection.Right
                dir = HTRIGHT
            Case ResizeDirection.BottomRight
                dir = HTBOTTOMRIGHT
            Case ResizeDirection.Bottom
                dir = HTBOTTOM
            Case ResizeDirection.BottomLeft
                dir = HTBOTTOMLEFT
        End Select
         If dir <> -1 Then
            ReleaseCapture()
            SendMessage(Me.Handle, WM_NCLBUTTONDOWN, dir, 0)
        End If
    End Sub


I attached the full example (without any compiled files, so you will probably need to Build it first) so you can play around with it.

Enjoy!

----------


## NickThissen

To move or resize any Control, you can use the attached class. It is basically the same code as the move/resize Form code, but now wrapped into a class.

Example usage is easy.
Simply create a new instance of the MoveControl class and pass the control you want to be able to resize. You can make multiple controls like this simply by creating multiple instances of the MoveControl class, with a different control each time.


vb.net Code:
Dim moveCtrl1 As New MoveControl(TextBox1)
Dim moveCtrl2 As New MoveControl(ProgressBar1)


*NEW:* You can now set some options such as AllowMoving, to enable or disable moving. You can also set the AllowResizingFlags property, to which you can pass a bitwise combination of flags (bottom, left, top, bottomleft, bottomright, etc) that the control can resize in.

Example usage:

vb.net Code:
'Create new MoveControl class to allow moving/resizing
        Dim moveCtrl As New MoveControl(ProgressBar1)
         'Disable moving
        moveCtrl.AllowMoving = False
         'Set resizing to horizontal and vertical only, no 'sideways' resizing:
        moveCtrl.AllowResizeFlags = MoveControl.ResizeDirection.Left Or _
                                    MoveControl.ResizeDirection.Right Or _
                                    MoveControl.ResizeDirection.Top Or _
                                    MoveControl.ResizeDirection.Bottom
         'On second thought, let's remove the Left resizing option:
        moveCtrl.AllowResizeFlags = moveCtrl.AllowResizeFlags And Not MoveControl.ResizeDirection.Left

As you can see, you use the "Or" operator to enable multiple directions as in the example (by default, all directions are enabled). 
To remove a single direction from the allowed directions, you can use the "And Not" operator as in the example.
Use "ResizeDirection.None" to disable resizing completely.

Any disabled resizing directions will also stop showing the resizing icon.


Also attached is a small example project.



Code in the class:

vb.net Code:
Imports System.Runtime.InteropServices
 Public Class MoveControl
     Private _ctrl As Control
    Public Sub New(ByVal ctrl As Control)
        _ctrl = ctrl
         If _ctrl IsNot Nothing Then
            AddHandler _ctrl.MouseDown, AddressOf MouseDown
            AddHandler _ctrl.MouseMove, AddressOf MouseMove
        Else
            Throw New ArgumentException("Object 'ctrl' not set to any control.")
        End If
    End Sub
 #Region " Options "
     Private _AllowMoving As Boolean = True
    Public Property AllowMoving() As Boolean
        Get
            Return _AllowMoving
        End Get
        Set(ByVal value As Boolean)
            _AllowMoving = value
        End Set
    End Property
     Private _AllowResizeFlags As ResizeDirection = ResizeDirection.Bottom Or _
                                                    ResizeDirection.BottomLeft Or _
                                                    ResizeDirection.BottomRight Or _
                                                    ResizeDirection.Left Or _
                                                    ResizeDirection.Right Or _
                                                    ResizeDirection.Top Or _
                                                    ResizeDirection.TopLeft Or _
                                                    ResizeDirection.TopRight
     Public Property AllowResizeFlags() As ResizeDirection
        Get
            Return _AllowResizeFlags
        End Get
        Set(ByVal value As ResizeDirection)
            _AllowResizeFlags = value
        End Set
    End Property
 #End Region
     'Width of the 'resizable border', the area where you can resize.
    Private Const BorderWidth As Integer = 6
    Private _resizeDir As ResizeDirection = ResizeDirection.None
     <Flags()> _
    Public Enum ResizeDirection
        None = 0
        Left = 1
        TopLeft = 2
        Top = 4
        TopRight = 8
        Right = 16
        BottomRight = 32
        Bottom = 64
        BottomLeft = 128
    End Enum
     Private Property resizeDir() As ResizeDirection
        Get
            Return _resizeDir
        End Get
        Set(ByVal value As ResizeDirection)
            _resizeDir = value
             'Change cursor
            Select Case value
                Case ResizeDirection.Left
                    _ctrl.Cursor = Cursors.SizeWE
                 Case ResizeDirection.Right
                    _ctrl.Cursor = Cursors.SizeWE
                 Case ResizeDirection.Top
                    _ctrl.Cursor = Cursors.SizeNS
                 Case ResizeDirection.Bottom
                    _ctrl.Cursor = Cursors.SizeNS
                 Case ResizeDirection.BottomLeft
                    _ctrl.Cursor = Cursors.SizeNESW
                 Case ResizeDirection.TopRight
                    _ctrl.Cursor = Cursors.SizeNESW
                 Case ResizeDirection.BottomRight
                    _ctrl.Cursor = Cursors.SizeNWSE
                 Case ResizeDirection.TopLeft
                    _ctrl.Cursor = Cursors.SizeNWSE
                 Case Else
                    _ctrl.Cursor = Cursors.Default
            End Select
        End Set
    End Property
 #Region " Functions and Constants "
     <DllImport("user32.dll")> _
    Public Shared Function ReleaseCapture() As Boolean
    End Function
     <DllImport("user32.dll")> _
    Public Shared Function SendMessage(ByVal hWnd As IntPtr, ByVal Msg As Integer, ByVal wParam As Integer, ByVal lParam As Integer) As Integer
    End Function
     Private Const WM_NCLBUTTONDOWN As Integer = &HA1
    Private Const HTBORDER As Integer = 18
    Private Const HTBOTTOM As Integer = 15
    Private Const HTBOTTOMLEFT As Integer = 16
    Private Const HTBOTTOMRIGHT As Integer = 17
    Private Const HTCAPTION As Integer = 2
    Private Const HTLEFT As Integer = 10
    Private Const HTRIGHT As Integer = 11
    Private Const HTTOP As Integer = 12
    Private Const HTTOPLEFT As Integer = 13
    Private Const HTTOPRIGHT As Integer = 14
 #End Region
 #Region " Moving & Resizing methods "
     Private Sub MoveControl(ByVal hWnd As IntPtr)
        ReleaseCapture()
        SendMessage(hWnd, WM_NCLBUTTONDOWN, HTCAPTION, 0)
    End Sub
     Private Sub ResizeControl(ByVal hWnd As IntPtr, ByVal direction As ResizeDirection)
        Dim dir As Integer = -1
        Select Case direction
            Case ResizeDirection.Left
                dir = HTLEFT
            Case ResizeDirection.TopLeft
                dir = HTTOPLEFT
            Case ResizeDirection.Top
                dir = HTTOP
            Case ResizeDirection.TopRight
                dir = HTTOPRIGHT
            Case ResizeDirection.Right
                dir = HTRIGHT
            Case ResizeDirection.BottomRight
                dir = HTBOTTOMRIGHT
            Case ResizeDirection.Bottom
                dir = HTBOTTOM
            Case ResizeDirection.BottomLeft
                dir = HTBOTTOMLEFT
        End Select
         If dir <> -1 Then
            ReleaseCapture()
            SendMessage(hWnd, WM_NCLBUTTONDOWN, dir, 0)
        End If
    End Sub
#End Region
 #Region " Event Handlers "
     Private Sub MouseMove(ByVal sender As Object, ByVal e As MouseEventArgs)
        If e.Location.X < BorderWidth And e.Location.Y < BorderWidth Then
            If (Me.AllowResizeFlags And ResizeDirection.TopLeft) = ResizeDirection.TopLeft Then resizeDir = ResizeDirection.TopLeft
         ElseIf e.Location.X < BorderWidth And e.Location.Y > _ctrl.Height - BorderWidth Then
            If (Me.AllowResizeFlags And ResizeDirection.BottomLeft) = ResizeDirection.BottomLeft Then resizeDir = ResizeDirection.BottomLeft
         ElseIf e.Location.X > _ctrl.Width - BorderWidth And e.Location.Y > _ctrl.Height - BorderWidth Then
            If (Me.AllowResizeFlags And ResizeDirection.BottomRight) = ResizeDirection.BottomRight Then resizeDir = ResizeDirection.BottomRight
         ElseIf e.Location.X > _ctrl.Width - BorderWidth And e.Location.Y < BorderWidth Then
            If (Me.AllowResizeFlags And ResizeDirection.TopRight) = ResizeDirection.TopRight Then resizeDir = ResizeDirection.TopRight
         ElseIf e.Location.X < BorderWidth Then
            If (Me.AllowResizeFlags And ResizeDirection.Left) = ResizeDirection.Left Then resizeDir = ResizeDirection.Left
         ElseIf e.Location.X > _ctrl.Width - BorderWidth Then
            If (Me.AllowResizeFlags And ResizeDirection.Right) = ResizeDirection.Right Then resizeDir = ResizeDirection.Right
         ElseIf e.Location.Y < BorderWidth Then
            If (Me.AllowResizeFlags And ResizeDirection.Top) = ResizeDirection.Top Then resizeDir = ResizeDirection.Top
         ElseIf e.Location.Y > _ctrl.Height - BorderWidth Then
            If (Me.AllowResizeFlags And ResizeDirection.Bottom) = ResizeDirection.Bottom Then resizeDir = ResizeDirection.Bottom
         Else
            resizeDir = ResizeDirection.None
        End If
    End Sub
     Private Sub MouseDown(ByVal sender As Object, ByVal e As MouseEventArgs)
        If e.Button = Windows.Forms.MouseButtons.Left Then
            If resizeDir = ResizeDirection.None Then
                If Me.AllowMoving Then MoveControl(_ctrl.Handle)
            Else
                If (Me.AllowResizeFlags And resizeDir) = resizeDir Then ResizeControl(_ctrl.Handle, resizeDir)
            End If
        End If
    End Sub
 #End Region
 End Class

----------


## NickThissen

I would just like to point out an observation I just made. It appears that there is a hardcoded minimum size for both forms and controls resized this way. Try to resize your browser window as small as you can. You will see that the minimum you can make it is as high as the caption bar, and as wide as the caption bar when only one letter of the caption is displayed. 
The same limit applies to any control resized using the method in the class above.

That this limit exists for forms is probably a good thing, but for controls I can imagine it giving unexplainable trouble. Hence, I decided to mention it. So now you know  :Smilie:

----------


## wenight

The Moving and Resizing a control a Control coding everything work perfect to me!!
But only the problem is if want to make the button move-able... the button cannot click and perform it's function.........

----------


## NickThissen

Can you try handling the MouseDown or MouseUp event instead of the Click event? Maybe that will work. It's not exactly the same as the Click event, but it may work for you.

If not, my only other idea is to create a UserControl, apply the movable class to _that_ UserControl, and then put a Button on the UserControl, in the center. Leave a border around the Button where you can see the background of the UserControl. If all is well, the user should be able to move and resize the button using the edge of the Usercontrol, but still be able to click the button.
Of course, the Button's properties must be exposed via properties if you want to use them, and you also need to expose any events the button receives.

----------


## pimvdb

Thanks, I didn't know using api would be faster than 'normal' resizing (doing calculations and use it with Me.Size) but this is really useful as a free ribbon control available on the internet has a lot of flickering and consumes almost all CPU because it is invalidating itself every time, and the resize method probably is not done with api.

----------


## wenight

I realize that it fail to move Label control...
anyone move?

----------


## NickThissen

I noticed that too. I've no idea why that happens. The label control must have something different. If it is crucial that you can move a label, you can also use a PictureBox, and simply paint the text yourself in the Paint event using the DrawString method. Dragging a Picturebox works fine.

----------


## softwareguy74

Pretty slick, but one problem off the bat is that auto scrolling doesn't work.  For example, when I set the Panel to AutoScroll = True, and I drag the progressbar off the side, the scrollbar doesn't automatically appear.

----------


## minitech

Take a look at the WndProc in here:
http://www.vbforums.com/showthread.php?t=596447
It seems to be a prettier way to make forms moveable & resizeable with all the confusing goodness of windows messages but no APIs!

----------


## NickThissen

> Take a look at the WndProc in here:
> http://www.vbforums.com/showthread.php?t=596447
> It seems to be a prettier way to make forms moveable & resizeable with all the confusing goodness of windows messages but no APIs!


Yes, I know about that. I don't see how it's prettier though. It comes down to the same thing. Whether I use SendMessage or override WndProc, I still need all the constants and stuff.

Also, I can't use the WndProc method for moving controls, because I'm not overriding any controls. With my MoveControl class you can simply specify which control you want to enable moving for and that's that.

----------


## JuggaloBrotha

Just implemented this code in one of my apps this morning Nick, I prefer this api method as it allows me to move controls in the same manor (same code).  Works wonderfully.

----------


## JuggaloBrotha

Well I've discovered that you don't even need a control on the form to drag the borderless window around.  Just define a Rectangle and in the MouseDown event check that rectangle if it contains the mouse coord's and to the drag thing, otherwise let the resize check happen.  Here's an example, it defines a rectangle spanning the entire top of the form, 30px in height (minus the resize border width of course)

```
    Private Const m_TitleHeight As Integer = 30I

    Private Sub Form1_MouseDown(ByVal sender As Object, ByVal e As System.Windows.Forms.MouseEventArgs) Handles Me.MouseDown
        If Me.DragRect.Contains(e.Location) Then
            ReleaseCapture()
            SendMessage(Me.Handle, WM_NCLBUTTONDOWN, HTCAPTION, 0I)
        Else
            If e.Button = MouseButtons.Left And Me.WindowState <> FormWindowState.Maximized Then ResizeForm(ResizeDir)
        End If
    End Sub

    Private ReadOnly Property DragRect() As Rectangle
        Get
            Return New Rectangle(m_BorderWidth, m_BorderWidth, Me.ClientSize.Width - (m_BorderWidth * 2I), m_TitleHeight)
        End Get
    End Property
```

You can still resize the window from the top edge vertically, diagonally, or horizontally respectively because the rectangle's bounds take that into account when it's created.

----------


## boops boops

Practically all the problems of borderless form dragging are now sorted out! But there is still one thing to be dealt with. The smooth-dragging methods work by letting the form or a selected rectangle behave like a title bar. You can drag the form as far as you like offscreen to the left, right or bottom. But not to the top! Windows Forms apparently don't like having their title bars moved off the top of the screen. You can drag the form up, but it bounces back down again as soon as you release the mouse button.

I wanted to change this behaviour so I spent some time looking at Windows messages. I found that the bounce-down behaviour was uniquely associated with a WM_CAPTURECHANGED message immediately followed by a WM_WINDOWPOSCHANGING. Then I managed to overcome the bounce with the following WndProc Sub:



```
 Const WM_CAPTURECHANGED As Integer = &H215
    Const WM_WINDOWPOSCHANGING As Int32 = &H46
    Const SWP_NOMOVE As Integer = &H2
  
<StructLayout(LayoutKind.Sequential, Pack:=1)> _
    Public Structure WINDOWPOS
        Public hwnd As Int32
        Public hWndInsertAfter As Int32
        Public x As Int32
        Public y As Int32
        Public cx As Int32
        Public cy As Int32
        Public flags As Int32
    End Structure

    Private dontMove As Boolean

    Protected Overrides Sub WndProc(ByRef m As System.Windows.Forms.Message)
        If Me.Top < 0 Then
            If m.Msg = WM_CAPTURECHANGED Then
                dontMove = True
            ElseIf m.Msg = WM_WINDOWPOSCHANGING AndAlso dontMove = True Then
                Dim wPos As WINDOWPOS = DirectCast _
                  (Runtime.InteropServices.Marshal.PtrToStructure _
                  (m.LParam, GetType(WINDOWPOS)), WINDOWPOS)
                wPos.flags = wPos.flags Or SWP_NOMOVE
                Runtime.InteropServices.Marshal.StructureToPtr(wPos, m.LParam, True)
                dontMove = False
            Else
                dontMove = False
            End If
        End If
        MyBase.WndProc(m)
    End Sub
```

The above code can simply be added to any form using your dragging method without further changes. Since you prefer using APIs to WndProc, you may wish to consider whether this can be translated into an API version. 

BB

----------


## JuggaloBrotha

> Practically all the problems of borderless form dragging are now sorted out! But there is still one thing to be dealt with. The smooth-dragging methods work by letting the form or a selected rectangle behave like a title bar. You can drag the form as far as you like offscreen to the left, right or bottom. But not to the top! Windows Forms apparently don't like having their title bars moved off the top of the screen. You can drag the form up, but it bounces back down again as soon as you release the mouse button.


I haven't used a Windows OS where that would happen.  The closest I've come across so far is in Win7 if you're moving a window up and the cursor enters the top screen zone it'll suggest maximizing the form, but right here in WinXP (I'm at work) I can have a window with the title bar partially off the screen at the top there (only the bottom half of the close button is visible right now)

----------


## boops boops

Yes, you can always drag a title bar to about 20 pixels above the top. But have you succeeded in dragging a borderless form any further than that, the same way as you can to left, right or bottom? BB

----------


## JuggaloBrotha

> Yes, you can always drag a title bar to about 20 pixels above the top. But have you succeeded in dragging a borderless form any further than that, the same way as you can to left, right or bottom? BB


Good point, I guess I'd never noticed that with borderless forms

----------


## NickThissen

There's a good reason for windows not allowing windows to go that high: you cannot grab the title bar to move them anymore... Obviously that does not need to apply to a borderless form, but since windows cannot know what area of your form you are using as the dragging part, it just enforces the same rule.

----------


## boops boops

> There's a good reason for windows not allowing windows to go that high: you cannot grab the title bar to move them anymore... Obviously that does not need to apply to a borderless form, but since windows cannot know what area of your form you are using as the dragging part, it just enforces the same rule.


Are you saying that Windows is stupider than we are? That would take some doing. BB

----------


## NickThissen

Well think about it... Windows may know whether a window is borderless or not, but it cannot possibly tell what region you have decided, in your code, to use as the dragging region. I am referring to JB's update on this, but it goes just as well for my original approach. So, since it cannot know that your resizing region may not be completely invisible if the window is at a certain height, it must conclude that there is a chance that moving the form that high would make it impossible to move it any further later. At least I assume that is the thought that went into this design. It's just the default window behavior in windows and goes for all windows, even borderless ones.

----------


## boops boops

Sorry, I didn't mean my last comment to be taken too seriously -- I just couldn't find the right smiley. Of course it was a logical design decision to prevent title bars being dragged so high you couldn't pull them back again. Sometimes you want to keep that behaviour for a borderless form; for example, if you have designed a custom title bar at the top. And there are plenty of other situations where it won't matter much. All the same, it is not consistent for a borderless form because it should be equally draggable in all directions.

I have been using this form dragging code (or its WndProc equivalent) for dragging Layered Windows for the purpose of compositing large partly-transparent images. In that case, the bounce behaviour is undesirable. That is why I tried to find a way of stopping it.

The WndProc and API codes for borderless form dragging have been in circulation for a few years now. But nobody seems to have noticed the "bouncing off the top" problem or thought it worth mentioning. I hope I have contributed something useful to this thread by pointing out the problem and offering a solution.

BB

----------


## Amerigo

Thank you very much, NickThissen! If I knew what you looked like, I would make an idle of you to worship. I guess a shrine will have to do...  :big yellow:

----------


## arcanine

This code is great!  It is so much smoother than trying to resize things through code!  I have two questions though:

1.  Is it possible to get the MoveControl to consistently resize when the control is within a TableLayoutPanel?  I was able to get a Panel contained within a cell of a TableLayoutPanel to resize by setting the Panel's Anchor to All, while setting the TableLayoutPanel Row and Column that contain the Panel to AutoSize.

However, I've found that the ability to resize the Panel stops working if the TableLayoutPanel's size is changed to a value that is different than the compiled value.  Strangely though, if the size is set back to the compiled size, the ability to resize is back!

2.  Is there a way to utilize a control's Minimum and Maximum sizes when resizing the control?  I've noticed that while resizing or moving a control on a form the cursor is prevented from leaving the form.  I think this is great, because it prevents a user from moving a control "off" the form.  However, controls can still be resized to cover other controls.  I thought I'd try and prevent this by setting the Max and Min Sizes, but the MoveControl class  doesn't seem to check those values when resizing.

Again, this is great code, I was just curious about some things.  Thanks.

----------


## NickThissen

1. This is probably due to the TableLayoutPanel taking control of the sizing in some way. I have no clue how to get around it, if it's possible at all.

2. Apparently the system doesn't check the minimum and maximum size of controls in the same way it does for forms. My code works by treating the control as a window and utilizes the system moving and resizing messages. The result is that the moving and resizing works as optimized as possible (this is why it's so smooth), but at the same time you have very little control over it. For example you can't go below a hardcoded minimum size (the same minimum size that every window in windows gets, try resizing your browser window as small as you can), this seems to be wired into the system somehow and I don't think there's any way around it.

Long story short: if the system ignores the minimum / maximum size properties of the controls, I doubt there's a way around it. You can try catching Resizing events (though I doubt they will be raised) and reset the value there, perhaps...

----------


## arcanine

I was afraid of that.  I'll do some more research and see if I can mix and match higher level .NET "bounds" checks with your API calls.  I'll get back to you sometime in the coming week.

----------


## JuggaloBrotha

arcanine, your best bet is probably going to be handling the MouseDown, MouseMove and MouseUp events of the window and do the move/resize yourself because you can control all aspects of it, like when moving around you can code it to have your borderless forms snap to each other or to the edge of the screen and when it comes to resizing you can take into consideration not only your form's MinimumSize property but the sizes of all the controls on the form too so the form, despite it's MinimumSize property, is never sized too small.

Ideally you'd figure out what the absolute minimum size of the form should be and put that into the MinimumSize property so you don't have it calculating all that stuff for each control on your form in real time, while it's resizing, that will help with the speed/smoothness of the resize too. This applies to whether you use the API or handle those actions yourself.

----------


## chathu1234

> Hi,
> 
> Here is a small example of how to move and resize a form without a border (FormBorderStyle = None).
> 
> Instead of manually setting the Location and Size of the Form, I have decided to use the SendMessage function to handle it. This results in a much smoother experience, (especially with lots of controls) and will also make sure that the form always follows the mouse, regardless of how fast you move it. In other examples you will often notice that if you move your mouse too fast, the form can no longer keep up and will stop moving. 
> 
> 
> The example uses a Panel as the form's caption. Dragging the panel will move the form, just like the real caption of a form with a border would behave.
> You can of course decide to use a different control. You could even use the form itself. I just thought a Panel was the easiest example.
> ...


Use this code to move the form.Its simpler



```
 Private Const WM_NCHITTEST As Integer = &H84
    Private Const HTCLIENT As Integer = &H1
    Private Const HTCAPTION As Integer = &H2

    Protected Overrides Sub WndProc(ByRef m As System.Windows.Forms.Message)
        Select Case m.Msg
            Case WM_NCHITTEST
                MyBase.WndProc(m)
                If m.Result = HTCLIENT Then
                    m.Result = HTCAPTION
                End If
            Case Else
                'Make sure you pass unhandled messages back to the default message handler.
                MyBase.WndProc(m)
        End Select
    End Sub
```

----------


## NickThissen

It comes down to the same thing in the end. Why is it simpler? It's more code and harder to understand imo.

----------


## minitech

It's a little more efficient, but that's not the point. It's a lot less flexible.

----------


## chathu1234

> It comes down to the same thing in the end. Why is it simpler? It's more code and harder to understand imo.


Im not questioning your code or your knowledge.I just posted a more memory efficient method

----------


## chathu1234

> It comes down to the same thing in the end. Why is it simpler? It's more code and harder to understand imo.


Your code needs a panel or some other component to work on.The code I posted does not need any component.Just paste the code in the form class and then you can move your form

----------


## NickThissen

It doesn't need a panel, you can just as well call my MoveForm code in the MouseClick of the Form itself. A Panel is just a neat example because that's a typical way to mimic a titlebar (you usually can't move a form from anywhere except the titlebar). 

I also wasn't shooting down your code or anything, it's just as nice because it basically comes down to the same thing. It's just a little less flexible as minitech mentions (what if the user does want to use a panel or other control to move the form?) and I think it is less easy to understand. In your case, a method called "WndProc" (which is not very descriptive of what it does in this case, and I know you can't help that cause you override it) which checks a 'Result' to some arbitrary values. In my case, a MouseClick event that calls a MoveForm method. I think in most cases especially less experienced people will understand what my code does even if they don't understand how, which might not be true for your code immediately (though some comments can always fix that).

But thanks for the contribution, always appreciated  :Smilie:

----------


## arcanine

I hate to resurrect an old thread, but I've started fooling with this code again.  Pertaining to moving a control within a form, I've noticed that the cursor cannot be moved outside of the client rectangle of the form that the control is on.  Does anyone know how windows determines the clip rectangle in this case?  I feel that if we can specify the clip rectangle (maybe using ClipCursor) then we can handle the control's Min/Max size.  If we are able to set the cursor clip, it would only take a little logic and math to get the clip rectangle right.

_Edit_

So I've managed to use the user32.dll ClipCursor function to limit the movement of the mouse.  However, when your code calls the SendMessage function, the ClipCursor bounds are reset.  I know almost nothing about the user32 functions, so I'm really over my head on this stuff.  I'm guessing though, by the other posts, that it's just not possible.  With my quick skim of the MSDN articles pertaining to user32.dll functions, it seems like it should be possible.

Excerpts from your code (without the ClipCursor stuff, since it didn't work):


```
    Private Sub MouseDown(ByVal sender As Object, ByVal e As MouseEventArgs)
        If e.Button = Windows.Forms.MouseButtons.Left Then
            If resizeDir = ResizeDirection.None Then
                If Me.AllowMoving Then MoveControl(_ctrl.Handle)
            Else
                If (Me.AllowResizeFlags And resizeDir) = resizeDir Then
                    ResizeControl(_ctrl.Handle, resizeDir)
                End If
            End If
        End If
    End Sub

    Private Sub ResizeControl(ByVal hWnd As IntPtr, ByVal direction As ResizeDirection)
        Dim dir As Integer = -1

        Select Case direction
            Case ResizeDirection.Left
                dir = HTLEFT
            Case ResizeDirection.TopLeft
                dir = HTTOPLEFT
            Case ResizeDirection.Top
                dir = HTTOP
            Case ResizeDirection.TopRight
                dir = HTTOPRIGHT
            Case ResizeDirection.Right
                dir = HTRIGHT
            Case ResizeDirection.BottomRight
                dir = HTBOTTOMRIGHT
            Case ResizeDirection.Bottom
                dir = HTBOTTOM
            Case ResizeDirection.BottomLeft
                dir = HTBOTTOMLEFT
        End Select

        If dir <> -1 Then
            ReleaseCapture()
            SendMessage(hWnd, WM_NCLBUTTONDOWN, dir, 0)
        End If
    End Sub
```

_Edit_

No ideas?

----------


## nbrege

Is there any way to make this work with a SplitContainer?  I have a  SplitContainer on my form & use the top panel as the titlebar & the bottom panel for controls.  I can make it work for moving the form, but not resizing.  It seems the SplitContainer prevents the move events from firing because it covers the form.  Any ideas?

----------


## Edgemeal

> Is there any way to make this work with a SplitContainer?  I have a  SplitContainer on my form & use the top panel as the titlebar & the bottom panel for controls.  I can make it work for moving the form, but not resizing.  It seems the SplitContainer prevents the move events from firing because it covers the form.  Any ideas?


Sure, you just need to modify it so the code is acting on the split container mouse events, maybe the attached (VS 2010) project give ya some ideas.

*EDIT* I didn't expect so many downloads, uploaded slightly cleaner version I did a few days after original posting.

----------


## nbrege

Thanks Edgemeal ... that's exactly what I was looking for.

----------


## LuckyLuke82

I know this is an old thread, but It's far best I've found regarding resizing borderless form. However, I see that you can minimize form to basically a dot on the screen. Is It possible to set min resize -  like Windows, for my form's title  ? This code is just above my knowledge and I don't see how I could do that. Thanks in advance.

----------


## JuggaloBrotha

> I know this is an old thread, but It's far best I've found regarding resizing borderless form. However, I see that you can minimize form to basically a dot on the screen. Is It possible to set min resize -  like Windows, for my form's title  ? This code is just above my knowledge and I don't see how I could do that. Thanks in advance.


You set the form's MinimumSize property to be a minimum width (use 0 for the height if you dont want to restrict height at all) that you want for the title to still be shown.

----------


## LuckyLuke82

> You set the form's MinimumSize property to be a minimum width (use 0 for the height if you dont want to restrict height at all) that you want for the title to still be shown.


After trying all sorts of things in MouseMove and some hours passing by I figured that one out on my own. I just digged too much into code I don't fully understand even now and forgot about form property at all  :Blush:  

I would delete my post earlier, but I don't know If I can. But maybe better this way, so that someone doesn't get caught in same trap  :Smilie:

----------


## LuckyLuke82

Hi guys, me again  :Big Grin: 

I took a liberty and slightly modified original code. There may be someone else who needs this in plenty borderless forms (like me) so I moved all into module to shorten things out under form's code. This way you can handle each form like this:



```
  Private Sub pnlCaption_MouseDown(ByVal sender As System.Object, ByVal e As System.Windows.Forms.MouseEventArgs) Handles pnlCaption.MouseDown
        If e.Button = Windows.Forms.MouseButtons.Left And Me.WindowState <> FormWindowState.Maximized Then
            MoveForm(Me)
        End If
    End Sub

    Private Sub pnlCaption_MouseMove(ByVal sender As System.Object, ByVal e As System.Windows.Forms.MouseEventArgs) Handles pnlCaption.MouseMove
        If Me.WindowState = FormWindowState.Maximized Then Return
        SetDirection(Me)
    End Sub

    Private Sub Form1_MouseDown(ByVal sender As System.Object, ByVal e As System.Windows.Forms.MouseEventArgs) Handles MyBase.MouseDown
        If e.Button = Windows.Forms.MouseButtons.Left And Me.WindowState <> FormWindowState.Maximized Then
            ResizeForm(Me, resizeDir(Me)) 'allow form resize and moving.
        End If
    End Sub

    Private Sub Form1_MouseMove(ByVal sender As System.Object, ByVal e As System.Windows.Forms.MouseEventArgs) Handles MyBase.MouseMove
        If Me.WindowState = FormWindowState.Maximized Then Return
        SetDirection(Me)
    End Sub
```

Sample is attached. I hope you don't mind NickThissen, and thanks again for sharing such a nice solution !!

----------

