Moving a Form by Clicking Anywhere in the Window

AID: 4146
  • Status: Published

3300 points

  • Bytrestan
  • TypeGeneral
  • Posted on2010-11-22 at 13:24:55
Awards
  • Community Pick
Normally a window is moved by clicking on the caption bar and dragging. You may want your user to be able to move borderless forms or move a form by clicking anywhere in the form without the limitation to the caption bar. There are many ways to do it. Two of the most commonly-seen solutions are:

Standard Three-Event Handling
Handle the mousedown, mouseup, mousemove events. You can set a "dragging now" flag in mousedown and record the initial mouse coordinates as the start point.   In mousemove event, calculate the delta between the current mouse position and the start point. Set the window's new location using this delta as deviation value so the window will follow the mouse movement.  Finally, set the "dragging now" flag to false to turn off the dragging.

It's a functional technique. But you need to handle three events and use flags and variables to accomplish the work.

Re-target Form-Dragging Events
A simpler way is to intercept the message loop of a form and re-target the mouse events hitting the client area and send them to the caption bar, as shown in the following code snippet:
private const int WM_NCHITTEST = 0x0084;
    private const int HTCLIENT = 1;
    private const int HTCAPTION = 2;
    protected override void WndProc(ref Message m)
    {
      base.WndProc(ref m);
      switch (m.Msg)
      {
        case WM_NCHITTEST:
          if (m.Result == (IntPtr)HTCLIENT)
          {
            m.Result = (IntPtr)HTCAPTION;
          }
          break;
      }
    }

                                    
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:

Select allOpen in new window


If we have 20 forms and if we want them to have the similar behavior, using "copy &  paste" to get the above sequence into each one of the 20 files would be nasty.  A clean way is to create a derived class from Windows.Form:
public class InterceptProcForm:Form
                                    
1:

Select allOpen in new window


and put the above codes in this class. Then you replace the default base class Form with InterceptProcForm for all your forms:    
public partial class Form1 : InterceptProcForm
                                    
1:

Select allOpen in new window


No more need to change your source codes -- all the forms are following your mouse now.

Handling User-Controls
The question now comes up:  "What if a form is completely covered by a user control?" Now the message in WndProc() that originated from controls will be redirected to the control's caption which is meaningless to a control and the form will stay there quietly.

The solution is to handle the mousemove event and flood it to its owner form, as shown in this link: C# borderless form move by usercontrol.

Once again we need to take code reuse into consideration. In the above link, a generic type FormDragPanel is used and user panels can inherit from it to move the underlying form. It's an improvement but not enough. There are tens (if not tons) of various types of user control; for some of them we may want the dragging capability and for others we would just keep them as it is. A common type derived from UserControl is not feasible because C# does not support multiple inheritance. A quick thought is to create a separate FormDragXxxx for each type of control: FormDragLabel, FormDragPictureBox, FormDragProgressBar, etc. But your work does not end here. You need to touch the Designer-generated code and add an event chain in your form for each of the controls.

Inspired by Marcel, here's a kind of "adapter" pattern I've used to resolve the scenario. Simply add the following class FormDragBase in your project.
public class FormDragBase : System.Windows.Forms.Form
    {
        public const int WM_NCLBUTTONDOWN = 0xA1;
        public const int HT_CAPTION = 0x2;

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

        protected override void OnMouseMove(System.Windows.Forms.MouseEventArgs e)
        {
            base.OnMouseMove(e);

            if (e.Button == System.Windows.Forms.MouseButtons.Left)
            {
                if (WindowState == FormWindowState.Normal)
                {
                    ReleaseCapture();
                    SendMessage(Handle, WM_NCLBUTTONDOWN, HT_CAPTION, 0);
                }
            }
        }

        public void AddDraggingControl(System.Windows.Forms.Control theControl)
        {
            theControl.MouseMove += new System.Windows.Forms.MouseEventHandler(OnControlMouseMove);
        }

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

                                    
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
34:
35:
36:
37:
38:
39:
40:
41:

Select allOpen in new window


Derive your own form from this base class, then add the controls for which you want them to be transferable; for instance:
public partial class Form1 : FormDragBase
    {
        public Form1()
        {
            InitializeComponent();
            AddDraggingControl(this.label1);
            AddDraggingControl(this.pictureBox1);
            AddDraggingControl(this.progressBar1);
        }
    }

                                    
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:

Select allOpen in new window


So... There you go.  Simple and easy!
Asked On
2010-11-22 at 13:24:55ID4146
Tags

move borderless form

Topic

Microsoft Visual C#.Net

Views
2146

Comments

Expert Comment

by: starlite551 on 2010-12-16 at 13:09:37ID: 22124

Or Simple Just Add this :........
Point refPoint;
protected override void OnMouseDown(object sender, MouseEventArgs e)
{
     refPoint = new Point(e.X,e.Y);  
}

protected override void OnMouseMove(object sender, MouseEventArgs e)
        {
            if (e.Button == MouseButtons.Left)
            {
                this.Left += e.X - p.X;
                this.Top += e.Y - p.Y;
            }
        }

                                        
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:

Select allOpen in new window

Author Comment

by: trestan on 2010-12-21 at 13:38:28ID: 22342

It's similiar to the first one introduced in the article. However, what if the form is covered by a control?

Expert Comment

by: systan on 2011-01-15 at 11:59:43ID: 22870

GOod article.

Expert Comment

by: systan on 2011-01-19 at 06:00:13ID: 22966

I voted yes;
But can you just
AddDraggingControlToAll_Object(); ?  You don't know too?

Author Comment

by: trestan on 2011-01-19 at 08:59:25ID: 22980

Not sure what exactly you want to do.

Expert Comment

by: starlite551 on 2011-02-05 at 12:12:56ID: 23552

You can always check whether the focus of Mouse Pointer is on a Control Or On the Form itself while moving this way :
Point p;
        protected override void OnMouseDown(MouseEventArgs e)
        {
            if (this.Bounds.Contains(Cursor.Position))
            {
                p = new Point(e.X, e.Y);    
            }
            
        }
        protected override void OnMouseMove(MouseEventArgs e)
        {
            if (e.Button == MouseButtons.Left)
            {
                Left += e.X - p.X;
                Top += e.Y - p.Y;
            }
        }
                                        
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:

Select allOpen in new window

Author Comment

by: trestan on 2011-02-06 at 08:07:53ID: 23585

Yes. You are right. Then you need to add the above code to every control to be transferable.

Add your Comment

Please Sign up or Log in to comment on this article.

Join Experts Exchange Today

Gain Access to all our Tech Resources

Get personalized answers

Ask unlimited questions

Access Proven Solutions

Search 3.2 million solutions

Read In-Depth How-To Guides

1000+ articles, demos, & tips

Watch Step by Step Tutorials

Learn direct from top tech pros

And Much More!

Your complete tech resource

See Plans and Pricing

30-day free trial. Register in 60 seconds.

Loading Advertisement...

Top Visual C# Experts

  1. kaufmed

    39,306

    0 points yesterday

    Profile
    Rank: Genius
  2. JamesBurger

    29,150

    0 points yesterday

    Profile
    Rank: Sage
  3. CodeCruiser

    16,200

    0 points yesterday

    Profile
    Rank: Genius
  4. AndyAinscow

    13,836

    0 points yesterday

    Profile
    Rank: Genius
  5. nishantcomp2512

    13,260

    0 points yesterday

    Profile
    Rank: Wizard
  6. emoreau

    8,800

    0 points yesterday

    Profile
    Rank: Genius
  7. jonnidip

    7,868

    0 points yesterday

    Profile
    Rank: Master
  8. Idle_Mind

    7,162

    0 points yesterday

    Profile
    Rank: Savant
  9. mas_oz2003

    6,750

    0 points yesterday

    Profile
    Rank: Genius
  10. Sudhakar-Pulivarthi

    6,532

    0 points yesterday

    Profile
    Rank: Guru
  11. Michael74

    6,018

    0 points yesterday

    Profile
    Rank: Wizard
  12. RolandDeschain

    6,000

    0 points yesterday

    Profile
    Rank: Sage
  13. ddayx10

    5,300

    0 points yesterday

    Profile
    Rank: Sage
  14. apeter

    5,232

    0 points yesterday

    Profile
    Rank: Sage
  15. TheLearnedOne

    5,000

    0 points yesterday

    Profile
    Rank: Savant
  16. navneethegde

    5,000

    0 points yesterday

    Profile
    Rank: Wizard
  17. mroonal

    4,900

    0 points yesterday

    Profile
    Rank: Sage
  18. naman_goel

    4,664

    0 points yesterday

    Profile
    Rank: Guru
  19. AhmedHindy

    4,500

    0 points yesterday

    Profile
  20. mlmcc

    4,000

    0 points yesterday

    Profile
    Rank: Savant
  21. UndefinedException

    4,000

    0 points yesterday

    Profile
  22. ged325

    3,468

    0 points yesterday

    Profile
    Rank: Genius
  23. keyu

    3,400

    0 points yesterday

    Profile
    Rank: Master
  24. nilhan

    3,200

    0 points yesterday

    Profile
  25. SStory

    3,136

    0 points yesterday

    Profile
    Rank: Sage

Hall Of Fame