2010-03-05 5 views
6

J'ai créé un contrôle personnalisé et je voudrais permettre aux utilisateurs de cliquer et de faire glisser mon contrôle comme s'ils faisaient glisser la barre de titre de la fenêtre. Quelle est la meilleure façon de procéder? Jusqu'ici, je n'ai pas réussi à tirer parti de la souris vers le bas, vers le haut et vers des événements à déchiffrer lorsque la fenêtre doit être déplacée.Contrôle qui simule le glissement de la barre de titre de la fenêtre

Répondre

10

En plus de mon autre réponse, vous pouvez le faire manuellement dans un contrôle comme celui-ci:

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; 
    } 
} 

EDIT: Testé et fixe - cela fonctionne maintenant en fait.

+0

Merci pour le code! –

5

La manière la plus efficace de le faire est de gérer la notification WM_NCHITTEST.

Override méthode WndProc du formulaire et ajoutez le code suivant:

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 
} 

Cependant, je ne pense pas que le message sera envoyé s'il y a un contrôle à ce moment-là.

+0

Je suis intrigué ... pouvez-vous élaborer? Comment diable fait-on ce qu'on demande? – echo

+0

@echo: Il indique à Windows que cette partie du formulaire est la barre de titre, qui peut être déplacée. Notez que cela permettra également de maximiser le formulaire en double-cliquant sur cette partie. – SLaks

+0

Hah, astuce, je n'ai jamais vu ça avant. Il m'a fallu une minute pour comprendre ce qui se passait ici! – Aaronaught

3

Si vous voulez faire une partie du formulaire se comporter comme la légende, l'astuce WM_NCHITTEST que SLaks a donné est la voie à suivre. Mais si vous voulez faire une fenêtre enfant, vous pouvez faire glisser le formulaire et il y a un autre moyen.

Fondamentalement, si vous envoyez un message WM_SYSCOMMAND à DefWindowProc avec l'ID de commande MOUSE_MOVE, Windows passera en mode glisser. C'est essentiellement la façon dont la légende le fait, mais en supprimant l'intermédiaire, nous pouvons initier ce glisser à partir d'une fenêtre enfant, et nous n'obtenons pas tous les autres comportements de légende.

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

Cela a fonctionné pour moi, mais j'ai dû changer ReleaseCapture pour n'avoir aucun argument. Voir [ReleaseCapture] (https://msdn.microsoft.com/fr-fr/library/windows/desktop/ms646261 (v = vs.85) .aspx) – Erroneous

Questions connexes