tags:

views:

823

answers:

3

I am creating a small modal form that is used in Winforms application. It is basically a progress bar of sorts. But I would like the user to be able to click anywhere in the form and drag it to move it around on the desktop while it is still being displayed.

How can I implement this behavior?

+5  A: 

Microsoft KB Article 320687 has a detailed answer to this question.

Basically, you override the WndProc method to return HTCAPTION to the WM_NCHITTEST message when the point being tested is in the client area of the form -- which is, in effect, telling Windows to treat the click exactly the same as if it had occured on the caption of the form.

private const int WM_NCHITTEST = 0x84;
private const int HTCLIENT = 0x1;
private const int HTCAPTION = 0x2;

protected override void WndProc(ref Message m)
{
   switch(m.Msg)
   {
      case WM_NCHITTEST:
         base.WndProc(ref m);
     if ((int)m.Result == HTCLIENT)
        m.Result = (IntPtr)HTCAPTION;
        return;
            break;
   }
   base.WndProc(ref m);
} 
Timothy Fries
A: 

The following code assumes that the ProgressBarForm form has a ProgressBar control with Dock property set to Fill

public partial class ProgressBarForm : Form
{
    private bool mouseDown;
    private Point lastPos;

    public ProgressBarForm()
    {
        InitializeComponent();
    }

    private void progressBar1_MouseMove(object sender, MouseEventArgs e)
    {
        if (mouseDown)
        {
            int xoffset = MousePosition.X - lastPos.X;
            int yoffset = MousePosition.Y - lastPos.Y;
            Left += xoffset;
            Top += yoffset;
            lastPos = MousePosition;
        }
    }

    private void progressBar1_MouseDown(object sender, MouseEventArgs e)
    {
        mouseDown = true;
        lastPos = MousePosition;
    }

    private void progressBar1_MouseUp(object sender, MouseEventArgs e)
    {
        mouseDown = false;
    }
}
aku
+2  A: 

Here is a way to do it using a P/Invoke.

public const int WM_NCLBUTTONDOWN = 0xA1;
public const int HTCAPTION = 0x2;
[DllImport("User32.dll")]
public static extern bool ReleaseCapture();
[DllImport("User32.dll")]
public static extern int SendMessage(IntPtr hWnd, int Msg, int wParam, int lParam);

void Form_Load(object sender, EventArgs e)
{
   this.MouseDown += new MouseEventHandler(Form_MouseDown);  
}

void Form_MouseDown(object sender, MouseEventArgs e)
{                        
    if (e.Button == MouseButtons.Left)
    {
     ReleaseCapture();
     SendMessage(Handle, WM_NCLBUTTONDOWN, HTCAPTION, 0);
    }
}
FlySwat
You need to have: using System.Runtime.InteropServices; for [DllImport()] to work.
Kamil Szot
In my project I used code similar to Timothy Fries's, but i like this one because you can use exactly the same technique to make form dragable by it's controls, like labels. The other technique make form dragable, but if you click on labels, it won't drag.
flamey