2010-03-05 27 views
6

He creado un control personalizado y me gustaría permitir que las personas hagan clic y arrastren mi control como si estuvieran arrastrando en la barra de título de la ventana. ¿Cuál es la mejor manera de hacer esto?Control que simula el arrastre de la barra de título de la ventana

Hasta ahora no he tenido éxito al mover el mouse hacia abajo, hacia arriba y mover eventos para descifrar cuándo se debe mover la ventana.

Respuesta

10

Además de mi otra respuesta, puede hacerlo de forma manual en un control de esta manera:

Point dragOffset; 

protected override void OnMouseDown(MouseEventArgs e) { 
    base.OnMouseDown(e); 
    if (e.Button == MouseButtons.Left) { 
     dragOffset = this.PointToScreen(e.Location); 
     var formLocation = FindForm().Location; 
     dragOffset.X -= formLocation.X; 
     dragOffset.Y -= formLocation.Y; 
    } 
} 

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

    if (e.Button == MouseButtons.Left) { 
     Point newLocation = this.PointToScreen(e.Location); 

     newLocation.X -= dragOffset.X; 
     newLocation.Y -= dragOffset.Y; 

     FindForm().Location = newLocation; 
    } 
} 

EDITAR: Probado y fija - esto ahora funciona realmente.

+0

¡Gracias por el código! –

5

La forma más efectiva de hacerlo es controlar la notificación WM_NCHITTEST.

reemplazar el método del formulario WndProc y agregue el código siguiente:

if (m.Msg == 0x0084) {    //WM_NCHITTEST 
    var point = new Point((int)m.LParam); 
    if(someRect.Contains(PointToClient(point)) 
     m.Result = new IntPtr(2); //HT_CAPTION 
} 

Sin embargo, no creo que el mensaje será enviado si hay un control en ese punto.

+0

Estoy intrigado ... ¿puedes dar más detalles? ¿Cómo demonios hace esto lo que se pide? – echo

+0

@echo: le dice a Windows que esa parte del formulario es la barra de título, que puede arrastrarse. Tenga en cuenta que esto también permitirá maximizar el formulario haciendo doble clic en esa parte. – SLaks

+0

Hah, buen truco, nunca había visto este. Me tomó un minuto descubrir lo que estaba pasando aquí! – Aaronaught

3

Si desea hacer que una parte del formulario se comporte como el título, el truco WM_NCHITTEST que dio SLaks es el camino a seguir. Pero si desea hacer que una ventana hija sea capaz de arrastrar el formulario y hay otra forma.

Básicamente, si envía un mensaje WM_SYSCOMMAND a DefWindowProc con el ID de comando MOUSE_MOVE, Windows entrará en modo de arrastre. Básicamente, cómo lo hace el subtítulo, pero al eliminar al intermediario, podemos iniciar este arrastre desde una ventana secundaria y no obtenemos todos los demás comportamientos de subtítulos.

public class form1 : Form 
{ 
    ... 

    [DllImport("user32.dll")] 
    static extern IntPtr DefWindowProc(IntPtr hWnd, uint uMsg, UIntPtr wParam, IntPtr lParam); 
    [DllImport("user32.dll")] 
    static extern bool ReleaseCapture(IntPtr hwnd); 

    const uint WM_SYSCOMMAND = 0x112; 
    const uint MOUSE_MOVE = 0xF012;  

    public void DragMe() 
    { 
    DefWindowProc(this.Handle, WM_SYSCOMMAND, (UIntPtr)MOUSE_MOVE, IntPtr.Zero); 
    } 


    private void button1_MouseDown(object sender, MouseEventArgs e) 
    { 
    Control ctl = sender as Control; 

    // when we get a buttondown message from a button control 
    // the button has capture, we need to release capture so 
    // or DragMe() won't work. 
    ReleaseCapture(ctl.Handle); 

    this.DragMe(); // put the form into mousedrag mode. 
    } 
+0

Esto funcionó para mí, pero tuve que cambiar ReleaseCapture para no tener argumentos. Ver [ReleaseCapture] (https://msdn.microsoft.com/en-us/library/windows/desktop/ms646261 (v = vs.85) .aspx) – Erroneous

Cuestiones relacionadas