Felix  RuthenbergVerschieben von Controls via Drag & Drop in WinForms Anwendungen


Problem:
Ähnlich unserer beliebten IDE soll es möglich sein Controls, die auf unserer Form platziert wurden mit Drag & Drop zu verschieben und so auf eine neue Stelle in unserer WinForm abzulegen.

Beispiel:
In dem Beispiel, das hier beschrieben ist geht es darum Buttons anzupacken und auf der Form an neuer Stelle abzulegen.  Dazu müssen mehrere Events des Buttons abgefragt werden wie folgt beschrieben.

Built-In Drag and Drop Funktionalität:
Auch wenn es verlockend klingt, aber was man allgemein unter Drag&Drop versteht hat nichts mit der Verschiebung von Controls zu tun.  Beim klassischen Drag&Drop geht es vielmehr darum Objekte aus einem Control zu entnehmen (oder auch das Control selbst) und dieses in einem anderen Control wieder fallen zu lassen.  Zur Demonstration dieser Funktionalität ist die Beispiel-Form zweigeteilt, im unteren Bereich enthält sie ein FlowLayoutPanel, dass Elemente vom Typ Button aufnehmen kann.  Die Vorgehensweise dazu ist weiter unten beschrieben.

Verschieben von Controls auf der Form:
Prinzipielle Vorgehensweise:
Im MouseMove Event wird die aktuelle Position des Mauszeigers abgefragt und die Location des Controls daraufhin geändert.
Problem:
Die MouseEventArgs geben nur die aktuelle Position der Maus innerhalb des Buttons wieder, wichtig ist allerdings die Position der Maus auf der Form.  Außerdem muss ein Offset beachtet werden, der die Position der Maus innerhalb des Buttons berücksichtigt, denn sonst würde beim Zuweisen der neuen Button-Location das Control immer am Mauszeiger “kleben”.
Lösung:
Mit Hilfe der Methode Control.PointToScreen(Point p) lässt sich für jede Position innerhalb eines Controls (und auch der Form selbst) die absolute Bildschirmkoordinate berechnen.  (Das beutet, dass man in die PointToScreen Methode des Controls eine Koordinate relativ zur linken oberen Ecke des Controls eintragen kann und man bekommt den Wert der Koordinate zurück, die sich rechnerisch aus der Distanz vom linken oberen Bildschirmrand und der angegeben Koordinate errechnet.)  Die Idee ist nun vor dem Verschieben (also beim MouseDown Event) die derzeitige Position der Form zu merken.  Genauer gesagt wird ein virtueller Punkt berechnet, der sich aus der Position der Form und der aktuellen Position des Mauszeigers innerhalb des Buttons ergibt.  Das ist der rote Punkt im Tafelbild.  Der Code dazu ist hier zu sehen:

private void btn_MouseDown(object sender, MouseEventArgs e)
{
  Button btn = sender as Button;
  ptStartPosition = this.PointToScreen(e.Location);
}

Beim Verschieben der Maus muss nun also die neue Koordinate berechnet werden, die angibt welche Position der Button in der Form einnehmen soll.  Der Wert ergibt sich aus der aktuellen Mausposition (natürlich wieder vom Bildschrimrand) minus dem zuvor errechneten virtuellen Punkt:

private void btn_MouseMove(object sender, MouseEventArgs e)
{
  Point ptEndPosition = btn.PointToScreen(e.Location);
  ptEndPosition.Offset(-ptStartPosition.X, -ptStartPosition.Y);
  btn.Location = ptEndPosition;
}

Damit sind alle Berechnung abgeschlossen und das Control kann einfach verschoben werden.

Fazit:
Viel Gedanken für ein bisschen Code, manchmal ist das halt so!

Das Tafelbild zum Artikel:

t

Nutzen der Drag&Drop Funktionalität:
Im Beispiel, das hier verwendet wird, ist neben dem Verschieben der Controls eine Drag&Drop Funktionalität eingebaut, die folgendermaßen aufgebaut ist:

Beim Ziehen eines Buttons (mit der linken Maustaste) soll es möglich sein, diesen Button dem FlowLayoutPanel im unteren Bildschirmbereich hinzuzufügen.  Dazu werden drei Events und ein Property benötigt:

Das FlowLayoutPanel (flowLayoutPanel1) muss in der Eigenschaft AllowDrop auf true gesetzt werden.

Im MouseDownEvent des entsprechenden Buttons muss die DoDragDrop Methode aufgerufen werden.  In ihr muss außerdem spezifiziert werden welche DragDrop Aktionen möglich sind.

private void btn_MouseDown(object sender, MouseEventArgs e)
{
  Button btn = sender as Button;
  btn.DoDragDrop(btn, DragDropEffects.Move);
}

Im DragEnter Event des flowLayoutPanel1 muss nun abgeprüft werden ob ein bekanntes Element hineingezogen wurde und der entsprechende DragDropEffekt angewandt werden:

private void flowLayoutPanel1_DragEnter(object sender, DragEventArgs e)
{
  if (e.Data.GetDataPresent(typeof(Button)))
    e.Effect = DragDropEffects.Move;
  else
    e.Effect = DragDropEffects.None;
}

Zu guter letzt führt das DragDrop Event des flowLayoutPanel1 die eigentliche Verschiebung des Buttons durch.  Dazu wird der Button von der Form gelöst und dem flowLayoutPanel1 hinzugefügt:

private void flowLayoutPanel1_DragDrop(object sender, DragEventArgs e)
{
  Button btn = e.Data.GetData(typeof(Button)) as Button;
  flowLayoutPanel1.Controls.Add(btn);
  this.Controls.Remove(btn);
}

Quellcode:
Das ganze kann zum Nachvollziehen und Ausprobieren hier heruntergeladen werden:
http://cid-fd4d63530af59c99.skydrive.live.com/self.aspx/.Public/DragAndDrop.zip



Kategorien: .Net;C#;Windows; 03.04.2009 11:40:51


 


Neuen Kommentar einfügen:

  Titel:     
  Name:  
  E-Mail:
  Kommentar:

 
 
 


Kommentare




© Copyright 2008 ppedv AG