Make a borderless form movable?
Asked Answered
F

20

131

Is there a way to make a form that has no border (FormBorderStyle is set to "none") movable when the mouse is clicked down on the form just as if there was a border?

Furze answered 20/10, 2009 at 6:53 Comment(0)
S
301

This article on CodeProject details a technique. Is basically boils down to:

public const int WM_NCLBUTTONDOWN = 0xA1;
public const int HT_CAPTION = 0x2;

[System.Runtime.InteropServices.DllImport("user32.dll")]
public static extern int SendMessage(IntPtr hWnd, int Msg, int wParam, int lParam);
[System.Runtime.InteropServices.DllImport("user32.dll")]
public static extern bool ReleaseCapture();

private void Form1_MouseDown(object sender, System.Windows.Forms.MouseEventArgs e)
{     
    if (e.Button == MouseButtons.Left)
    {
        ReleaseCapture();
        SendMessage(Handle, WM_NCLBUTTONDOWN, HT_CAPTION, 0);
    }
}

This essentially does exactly the same as grabbing the title bar of a window, from the window manager's point of view.

Silicate answered 20/10, 2009 at 6:58 Comment(7)
This doesn't work for me at all. Code runs just fine, everything is correct, and my window is still just sitting there. Any ideas?Semeiology
@Semeiology You probably copied the code, that won't work as Form1_MouseDown is not assigned to the actual MouseDown event of Form1.Pomfrey
If you have a label or an icon (or any other foreground objects!) where you are grabbing the form to drag, add a mousedown event to these items too. Form events can't see through form objects.Nefarious
You need to add this.MouseDown += ... to the Main() function for the formSemiramis
Worked like a charm for me!!!! I had to move the event handling to the panel I was putting in place of the form but it workedMorse
This works great except that some mouse event handlers can't accept left button click.Memphis
OnMouseDoubleClick does not work and failed.Ukulele
P
78

Let's not make things any more difficult than they need to be. I've come across so many snippets of code that allow you to drag a form around (or another Control). And many of them have their own drawbacks/side effects. Especially those ones where they trick Windows into thinking that a Control on a form is the actual form.

That being said, here is my snippet. I use it all the time. I'd also like to note that you should not use this.Invalidate(); as others like to do because it causes the form to flicker in some cases. And in some cases so does this.Refresh. Using this.Update, I have not had any flickering issues:

private bool mouseDown;
private Point lastLocation;

    private void Form1_MouseDown(object sender, MouseEventArgs e)
    {
        mouseDown = true;
        lastLocation = e.Location;
    }

    private void Form1_MouseMove(object sender, MouseEventArgs e)
    {
        if(mouseDown)
        {
            this.Location = new Point(
                (this.Location.X - lastLocation.X) + e.X, (this.Location.Y - lastLocation.Y) + e.Y);

            this.Update();
        }
    }

    private void Form1_MouseUp(object sender, MouseEventArgs e)
    {
        mouseDown = false;
    }
Prickly answered 3/7, 2014 at 19:32 Comment(10)
dang winforms... looked for this answer for nearly two hours.... im new to c# though, you did me wonders!Spindry
This is exactly the way I thought of, my only issue was it was buggy as all hell until I read how you did it. Thanks mateRosaliarosalie
This one worked better for me than the amazing tiny snippet above the overrides WndProc. Mind you, the WndProc did work ... it just stopped other things from working. Thanks!Draughtsman
Probably the best option here as it works nicely and doesn't rely on WndProc (can easily be ported to other platforms with Mono). Can be improved by changing the state to maximized/normal if Y<10Coopt
It does not work on mono, changed .net 4.5.2 to mono/net 4.5 and still does not work. Trying to find a solution now.Sue
this is good. a couple issues. 1) gets messed up by double clicks. only set mouseDown = true if e.Clicks == 1. 2) this doesn't work if you have controls (panels) on your form. what I do is hook the events of most controls on the form, except for some kinds that don't make sense like buttons.Gluck
Absolutely the right solution here, even in 2021Demonography
Simple and easy. Worked for me in 2022.Avionics
this doesn't seem to work for me. I don't know whyCf
Fantastic solution. I implemented it in minutes and it works greatUsquebaugh
K
44

Another simpler way to do the same thing.

public partial class Form1 : Form
{
    public Form1()
    {
        InitializeComponent();
        // set this.FormBorderStyle to None here if needed
        // if set to none, make sure you have a way to close the form!
    }
    protected override void WndProc(ref Message m)
    {
        base.WndProc(ref m);
        if (m.Msg == WM_NCHITTEST)
            m.Result = (IntPtr)(HT_CAPTION);
    }

    private const int WM_NCHITTEST = 0x84;
    private const int HT_CLIENT = 0x1;
    private const int HT_CAPTION = 0x2;
}
Katydid answered 11/7, 2014 at 6:10 Comment(2)
Anyone of making it possible that you can move the form by holding a specific tool (eg a label).Exaggeration
If double-clicked, the form gets maximized. Also read here and there that this breaks right-clicking.Rap
T
20

use MouseDown, MouseMove and MouseUp. You can set a variable flag for that. I have a sample, but I think you need to revise.

I am coding the mouse action to a panel. Once you click the panel, your form will move with it.

//Global variables;
private bool _dragging = false;
private Point _offset;
private Point _start_point=new Point(0,0);


private void panel1_MouseDown(object sender, MouseEventArgs e)
{
   _dragging = true;  // _dragging is your variable flag
   _start_point = new Point(e.X, e.Y);
}

private void panel1_MouseUp(object sender, MouseEventArgs e)
{
   _dragging = false; 
}

private void panel1_MouseMove(object sender, MouseEventArgs e)
{
  if(_dragging)
  {
     Point p = PointToScreen(e.Location);
     Location = new Point(p.X - this._start_point.X,p.Y - this._start_point.Y);     
  }
}
Tailband answered 20/10, 2009 at 7:30 Comment(1)
It is. As said elsewhere already, this relies on the form still generating MouseMove events. As a simple case, suppose you grad the Form at the top-most pixel row and drag upwards. Nothing will happen, although the form will jump around as soon as you move the mouse back onto it.Silicate
B
13

WPF only


don't have the exact code to hand, but in a recent project I think I used MouseDown event and simply put this:

frmBorderless.DragMove();

Window.DragMove Method (MSDN)

Bigoted answered 20/10, 2009 at 7:5 Comment(3)
That's WPF, though. Ok, the OP didn't exactly specify this.Silicate
Yeah, which is something I forgot about the project I was doing. I just looked at Forms and it's not available. Sorry!Bigoted
@Bigoted This worked for me in a WPF project. Thanks for not deleting the answer.Terrenceterrene
P
13

It worked for Me.

    private Point _mouseLoc;

    private void Form1_MouseDown(object sender, MouseEventArgs e)
    {
        _mouseLoc = e.Location;
    }

    private void Form1_MouseMove(object sender, MouseEventArgs e)
    {
        if (e.Button == MouseButtons.Left)
        {
            int dx = e.Location.X - _mouseLoc.X;
            int dy = e.Location.Y - _mouseLoc.Y;
            this.Location = new Point(this.Location.X + dx, this.Location.Y + dy);
        }
    }
Plumb answered 11/8, 2019 at 17:5 Comment(1)
Yeah, if simple works fine why need to go complex. 🤓Plumb
S
9

Ref. video Link

This is tested and easy to understand.

protected override void WndProc(ref Message m)
{
    switch (m.Msg)
    {
        case 0x84:
            base.WndProc(ref m);
            if((int)m.Result == 0x1)
                m.Result = (IntPtr)0x2;
            return;
    }

    base.WndProc(ref m);
}
Shurlocke answered 10/2, 2015 at 17:19 Comment(3)
This code works, but how is it easy to understand? I don't know about anything in this code segment besides the switch statement!Diplomatist
This is WM_NCHITTEST in disguise.Elk
@JamshaidK. Only winapi developer will understand. WndProc form low level api where all events are controlled like form created, control added, deleted .... So he simply edited WndProc.Epifocal
T
5

Since some answers do not allow for child controls to be draggable, I've created a little helper class. It should be passed the top level form. Can be made more generic if desired.

class MouseDragger
{
    private readonly Form _form;
    private Point _mouseDown;

    protected void OnMouseDown(object sender, MouseEventArgs e)
    {
        _mouseDown = e.Location;
    }

    protected void OnMouseMove(object sender, MouseEventArgs e)
    {
        if (e.Button == MouseButtons.Left)
        {
            int dx = e.Location.X - _mouseDown.X;
            int dy = e.Location.Y - _mouseDown.Y;
            _form.Location = new Point(_form.Location.X + dx, _form.Location.Y + dy);
        }
    }
    public MouseDragger(Form form)
    {
        _form = form;

        MakeDraggable(_form);            
    }

    private void MakeDraggable(Control control)
    {
        var type = control.GetType();
        if (typeof(Button).IsAssignableFrom(type))
        {
            return;
        }

        control.MouseDown += OnMouseDown;
        control.MouseMove += OnMouseMove;

        foreach (Control child in control.Controls)
        {
            MakeDraggable(child);
        }
    }
}
Tyndareus answered 20/6, 2018 at 9:54 Comment(0)
H
4

There's no property you can flip to make this just happen magically. Look at the events for the form and it becomes fairly trivial to implement this by setting this.Top and this.Left. Specifically you'll want to look at MouseDown, MouseUp and MouseMove.

Haematopoiesis answered 20/10, 2009 at 6:56 Comment(3)
I figured I would have to use those events but I am not sure what to do with them. When the MouseDown event is called, how do I allow the form to be moved?Furze
On mouse down you set a flag and store the base coordinates. On mouse move - if the flag is set - you adjust the top and left by the offset of the new mouse coordinates. On mouse up you clear the flag.Takahashi
Still, you can do this with the Windows API fairly easy which doesn't depend on still getting mouse events. This method does fail if you grab at a pixel at the very top edge of the form and drag upwards, for example.Silicate
A
4
public Point mouseLocation;
private void frmInstallDevice_MouseDown(object sender, MouseEventArgs e)
{
  mouseLocation = new Point(-e.X, -e.Y);
}

private void frmInstallDevice_MouseMove(object sender, MouseEventArgs e)
{
  if (e.Button == MouseButtons.Left)
  {
    Point mousePos = Control.MousePosition;
    mousePos.Offset(mouseLocation.X, mouseLocation.Y);
    Location = mousePos;
  }
}

this can solve ur problem....

Addax answered 21/2, 2013 at 7:41 Comment(1)
You can also use "e.Location" instead of Control.MousePositionEcospecies
H
4

https://social.msdn.microsoft.com/Forums/vstudio/en-US/d803d869-68e6-46ff-9ff1-fabf78d6393c/how-to-make-a-borderless-form-in-c?forum=csharpgeneral

This bit of code from the above link did the trick in my case :)

protected override void OnMouseDown(MouseEventArgs e)  

{
      base.OnMouseDown(e);
      if (e.Button == MouseButtons.Left)
      {
        this.Capture = false;
        Message msg = Message.Create(this.Handle, 0XA1, new IntPtr(2), IntPtr.Zero);
        this.WndProc(ref msg);
      }
}
Hubby answered 26/9, 2016 at 6:44 Comment(0)
M
4

Best way I've found (modified of course)

// This adds the event handler for the control
private void AddDrag(Control Control) { Control.MouseDown += new System.Windows.Forms.MouseEventHandler(this.DragForm_MouseDown); }
public const int WM_NCLBUTTONDOWN = 0xA1;
public const int HT_CAPTION = 0x2;
[System.Runtime.InteropServices.DllImportAttribute("user32.dll")]
public static extern int SendMessage(IntPtr hWnd, int Msg, int wParam, int lParam);
[System.Runtime.InteropServices.DllImportAttribute("user32.dll")]
public static extern bool ReleaseCapture();

private void DragForm_MouseDown(object sender, MouseEventArgs e)
{
    if (e.Button == MouseButtons.Left)
    {
        ReleaseCapture();
        SendMessage(Handle, WM_NCLBUTTONDOWN, HT_CAPTION, 0);
        // Checks if Y = 0, if so maximize the form
        if (this.Location.Y == 0) { this.WindowState = FormWindowState.Maximized; }
    }
}

To apply drag to a control simply insert this after InitializeComponent()

AddDrag(NameOfControl);
Mccune answered 20/7, 2017 at 14:15 Comment(0)
G
2

For .NET Framework 4,

You can use this.DragMove() for the MouseDown event of the component (mainLayout in this example) you are using to drag.

private void mainLayout_MouseDown(object sender, MouseButtonEventArgs e)
{
    this.DragMove();
}
Grief answered 23/4, 2016 at 13:57 Comment(1)
This doesn't work, .NET 4 doesn't have any DragMove() function a form. What's mainLayout anyways??Zamarripa
B
2

I was trying to make a borderless windows form movable which contained a WPF Element Host control and a WPF User control.

I ended up with a stack panel called StackPanel in my WPF user control which seemed the logical thing to try click on to move. Trying junmats's code worked when I moved the mouse slowly, but if I moved the mouse faster, the mouse would move off the form and the form would be stuck somewhere mid move.

This improved on his answer for my situation using CaptureMouse and ReleaseCaptureMouse and now the mouse does not move off the form while moving it even if I move it quickly.

private void StackPanel_MouseDown(object sender, MouseButtonEventArgs e)
{
    _start_point = e.GetPosition(this);
    StackPanel.CaptureMouse();
}

private void StackPanel_MouseUp(object sender, MouseButtonEventArgs e)
{
    StackPanel.ReleaseMouseCapture();
}

private void StackPanel_MouseMove(object sender, MouseEventArgs e)
{
    if (StackPanel.IsMouseCaptured)
    {
        var p = _form.GetMousePositionWindowsForms();
        _form.Location = new System.Drawing.Point((int)(p.X - this._start_point.X), (int)(p.Y - this._start_point.Y));
    }
}

    //Global variables;
    private Point _start_point = new Point(0, 0);
Blastula answered 9/8, 2016 at 21:22 Comment(0)
E
2

Easiest way is:

First create a label named label1. Go to label1's events > mouse events > Label1_Mouse Move and write these:

if (e.Button == MouseButtons.Left){
    Left += e.X;
    Top += e.Y;`
}
Ene answered 1/2, 2017 at 13:0 Comment(0)
C
2

I'm expanding the solution from jay_t55 with one more method ToolStrip1_MouseLeave that handles the event of the mouse moving quickly and leaving the region.

private bool mouseDown;
private Point lastLocation;

private void ToolStrip1_MouseDown(object sender, MouseEventArgs e) {
    mouseDown = true;
    lastLocation = e.Location;
}

private void ToolStrip1_MouseMove(object sender, MouseEventArgs e) {
    if (mouseDown) {
        this.Location = new Point(
            (this.Location.X - lastLocation.X) + e.X, (this.Location.Y - lastLocation.Y) + e.Y);

        this.Update();
    }
}

private void ToolStrip1_MouseUp(object sender, MouseEventArgs e) {
    mouseDown = false;
}

private void ToolStrip1_MouseLeave(object sender, EventArgs e) {
    mouseDown = false;
}
Constancy answered 4/6, 2019 at 7:50 Comment(0)
T
1

Also if you need to DoubleClick and make your Form bigger/smaller , you can use the First answer, create a global int variable, add 1 every time user clicks on the component you use for dragging. If variable == 2 then make your form bigger/smaller. Also use a timer for every half a sec or a second to make your variable = 0;

Thee answered 16/11, 2016 at 20:10 Comment(0)
B
1

Adding a MouseLeftButtonDown event handler to the MainWindow worked for me.

In the event function that gets automatically generated, add the below code:

base.OnMouseLeftButtonDown(e);
this.DragMove();
Buff answered 19/6, 2018 at 7:45 Comment(0)
C
1

Form1(): new Moveable(control1, control2, control3);

Class:

using System;
using System.Windows.Forms;

class Moveable
{
    public const int WM_NCLBUTTONDOWN = 0xA1;
    public const int HT_CAPTION = 0x2;
    [System.Runtime.InteropServices.DllImportAttribute("user32.dll")]
    public static extern int SendMessage(IntPtr hWnd, int Msg, int wParam, int lParam);
    [System.Runtime.InteropServices.DllImportAttribute("user32.dll")]
    public static extern bool ReleaseCapture();
    public Moveable(params Control[] controls)
    {
        foreach (var ctrl in controls)
        {
            ctrl.MouseDown += (s, e) =>
            {
                if (e.Button == MouseButtons.Left)
                {
                    ReleaseCapture();
                    SendMessage(ctrl.FindForm().Handle, WM_NCLBUTTONDOWN, HT_CAPTION, 0);
                    // Checks if Y = 0, if so maximize the form
                    if (ctrl.FindForm().Location.Y == 0) { ctrl.FindForm().WindowState = FormWindowState.Maximized; }
                }
            };
        }
    }
}
Connective answered 11/4, 2020 at 14:11 Comment(0)
C
-2

I tried the following and presto changeo, my transparent window was no longer frozen in place but could be moved!! (throw away all those other complex solutions above...)

   private void Window_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
    {
        base.OnMouseLeftButtonDown(e);
        // Begin dragging the window
        this.DragMove();
    }
Caracole answered 20/7, 2018 at 16:4 Comment(1)
This answer is for WPF, the question is about WinForms.Propitious

© 2022 - 2024 — McMap. All rights reserved.