2010-03-05 7 views
6

Ich habe ein benutzerdefiniertes Steuerelement erstellt, und ich möchte zulassen, dass Benutzer auf mein Steuerelement klicken und ziehen, als würden sie die Titelleiste des Fensters ziehen. Was ist der beste Weg, dies zu tun?Steuerelement, das das Ziehen der Titelleiste des Fensters simuliert

Bis jetzt war ich erfolglos bei der Nutzung der Maus nach unten, nach oben und verschiebe Ereignisse zu entschlüsseln, wenn das Fenster verschoben werden muss.

Antwort

10

Neben meiner anderen Antwort, können Sie dies wie folgt in einer Steuerung manuell tun:

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: Geprüft und fixiert - das nun tatsächlich funktioniert.

+0

Danke für den Code! –

5

Der effektivste Weg, dies zu tun, ist die WM_NCHITTEST Benachrichtigung zu behandeln.

den folgenden Code überschreibt das WndProc-Methode des Formulars und fügt:

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 
} 

Aber ich glaube nicht, die Nachricht gesendet wird, wenn es eine Kontrolle an diesem Punkt ist.

+0

Ich bin fasziniert ... können Sie es ausarbeiten? Wie um alles in der Welt macht das, was gefragt wird? – echo

+0

@echo: Es teilt Windows mit, dass dieser Teil des Formulars die Titelleiste ist, die gezogen werden kann. Beachten Sie, dass dadurch auch das Formular maximiert werden kann, indem Sie auf dieses Teil doppelklicken. – SLaks

+0

Hah, ordentlicher Trick, ich habe das noch nie zuvor gesehen. Ich brauchte eine Minute, um herauszufinden, was hier vor sich ging! – Aaronaught

3

Wenn Sie möchten, dass ein Teil des Formulars sich wie die Überschrift verhält, ist der WM_NCHITTEST Trick, den SLaks gab, der richtige Weg. Aber wenn Sie ein untergeordnetes Fenster erstellen möchten, können Sie das Formular ziehen und es gibt einen anderen Weg.

Wenn Sie eine WM_SYSCOMMAND-Nachricht an DefWindowProc mit der Befehls-ID MOUSE_MOVE senden, wird Windows in den Drag-Modus gehen. Im Grunde genommen, wie die Überschrift es tut, aber indem wir den mittleren Mann ausschneiden, können wir diesen Ziehvorgang aus einem untergeordneten Fenster einleiten, und wir erhalten nicht alle anderen Untertitelverhalten.

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

Das funktionierte für mich, aber ich musste ReleaseCapture ändern, um keine Argumente zu haben. Siehe [ReleaseCapture] (https://msdn.microsoft.com/en-us/library/windows/desktop/ms646261 (v = vs.85) .aspx) – Erroneous

Verwandte Themen