Laden...

Treeview: Drag&Drop von Collapse/Expand unterscheiden

Erstellt von Christel vor 11 Jahren Letzter Beitrag vor 11 Jahren 1.645 Views
C
Christel Themenstarter:in
448 Beiträge seit 2007
vor 11 Jahren
Treeview: Drag&Drop von Collapse/Expand unterscheiden

Hallo,
ich habe für meinen TreeView Drag&Drop implementiert, um die Knoten zu sortieren.
Die DoDragDrop()-Methode rufe ich im MouseDown-Eventhandler auf.
Funktioniert auch super.

Das Problem tritt erst auf, wenn ich Knoten des TreeVies auf- oder zuklappe (Expand/Collapse). In diesem Falle lande ich im gleichen Eventhandler. Die nachfolgende DragDrop-Eventbehandlung hat dann unangenehme Nebeneffekte.

Wie kann ich erkennen, dass hier nicht einfach MouseDown, sondern Expand/Collapse stattfindet? Ich habe es bereits mittels der BeforeExpand/BeforeCollape-Ereignisse versucht, leider werden diese aber erst nach dem MouseDown geworfen.

Danke, Christel

Es ist schlimm, eine Ausnahme zu sein, aber noch schlimmer, keine zu sein.

106 Beiträge seit 2011
vor 11 Jahren

Hallo Christel,

Warum benutzt du das MouseDown-Event und nicht die DragDrop, DragEnter, DragLeave und DragOver Events?

MfG
Rabban

T
708 Beiträge seit 2008
vor 11 Jahren

Hallo Christel,

genau dafür gibt es dich die Events: DragDrop, DragEnter, DragLeave und DragOver.
Weshalb also per Click-Event das "Draggen" starten?

Im DragOver kann man entscheiden, ob überhaupt ein Droppen erlaubt sein soll und ein entsprechendes Icon anzeigen (e.Effect = DragDropEffects.Move;).
Im DragDrop dann behandeln, wenn die Node losgelassen wurde.

PS: Zu spät, dafür aber mehr Infos 😉

C
Christel Themenstarter:in
448 Beiträge seit 2007
vor 11 Jahren

DragDrop, und DragEnter verwende ich bereits.

Im MouseDown rufe ich DoDragDrop() auf.
Im DragEnter entscheide ich, ob Drop erlaubt ist.
Im DragDrop führe ich die Sortierung durch.

Es sit mir klar, dass das DoDragDrop() im MouseDouwn das Problem ist.
Aber wohin damit?
Ins DragLeave?

Werde ich mal nachlesen.

Danke, Christel

Es ist schlimm, eine Ausnahme zu sein, aber noch schlimmer, keine zu sein.

4.938 Beiträge seit 2008
vor 11 Jahren

Hallo Christel,

du kannst mittels HitTest() und Abfrage der Location überpüfen, wo der Mauszeiger steht, ob (bzw. bevor) du DoDragDrop() aufrufst.

P.S. Rabban und trib: diese Events werden aber erst ausgeführt, wenn man auch irgendwo vorher DoDragDrop() aufgerufen hat, und das macht man passenderweise im OnMouseDown.

C
Christel Themenstarter:in
448 Beiträge seit 2007
vor 11 Jahren

Stimmt, die Drag... Ereignisse kommen nach dem DoDragDrop()-Aufruf.
Der MouseDown-Ereignishandler ist also doch die richtige Stelle.

Die Mouseposition auszuwerten hatte ich auch schon in Erwägung gezogen. Ich müsste also rekursiv die Verschachtelungstiefe des Knotens bestimmen, daraus die zugehörige Expand/Collapse-Clickposition berechnen und mit der aktuellen Position vergleichen?

Kann ich so probieren.

Danke, Christel

Es ist schlimm, eine Ausnahme zu sein, aber noch schlimmer, keine zu sein.

4.938 Beiträge seit 2008
vor 11 Jahren

Ich dachte eher daran direkt zu vergleichen:


var info = treeView.Hittest(e.X, e.Y);
if (!info.Location.HasFlag(TreeViewHitTestLocations.PlusMinus))
{
   DoDragDrop(...);
}

Also nur das Draggen zu starten, wenn man nicht auf das Plus- oder Minus-Icon geklickt hat.

P.S. Mittels info.Node erhältst du auch gleich den zugehörigen Knoten, den du dann der DoDragDrop()-Methode als Parameter übergeben kannst (sofern != null).

C
Christel Themenstarter:in
448 Beiträge seit 2007
vor 11 Jahren

Coole Sache, funzt super.
Ich danke Dir, Christel

Es ist schlimm, eine Ausnahme zu sein, aber noch schlimmer, keine zu sein.

T
708 Beiträge seit 2008
vor 11 Jahren

P.S. Rabban und trib: diese Events werden aber erst ausgeführt, wenn man auch irgendwo vorher DoDragDrop() aufgerufen hat, und das macht man passenderweise im OnMouseDown.

Dafür würde ich dann das ItemDrag-Event nutzen. Dafür isses da 😃
MouseClick nutze ich nur um z.B. Cut, Copy & Paste als ToolStripMenue anzuzeigen und dynamisch die MenuItems anzuzeigen. Ggf. noch um Zusatzinformationen unter dem TreeView einzublenden.

C
Christel Themenstarter:in
448 Beiträge seit 2007
vor 11 Jahren

ItemDrag-Event ... wieder was gelernt, Christel

Es ist schlimm, eine Ausnahme zu sein, aber noch schlimmer, keine zu sein.

C
2.121 Beiträge seit 2010
vor 11 Jahren

Drag startet man am sinnvollsten erst dann, wenn die "gedrückte Maus" ein paar Pixel bewegt wird. Dann hat man kein Problem mit einem einfachen Klick, bei dem man normalerweise keine Bewegung macht.
Also beim MouseDown den Klickpunkt merken. Im MouseMove prüfen wie weit der Cursor vom Klickpunkt weg ist und dann erst DragDrop starten. Im MouseUp den Klickpunkt löschen, damit ein folgender MouseMove nicht mehr rechnet.

5.658 Beiträge seit 2006
vor 11 Jahren

Hallo allerseits,

ich habe dafür folgende Konstruktion, die auf die SystemParameters.MinimumHorizontalDragDistance und SystemParameters.MinimumVerticalDragDistance zurückgreift:


		void OnMouseDown(object sender, MouseButtonEventArgs e)
		{
			dragSource = null;
			dragSourceData = null;

			if (e.ChangedButton == MouseButton.Left)
			{
				dragSource = sender as FrameworkElement;
				mouseClickPosition = e.GetPosition(dragSource);

				if (dragSource != null)
				{
					dragSourceData = dragSource.DataContext as IViewModel;
				}

			}
		}


		void OnMouseMove(object sender, MouseEventArgs e)
		{
			// Can Drag?
			if (dragSourceData == null)
				return;

			if (e.LeftButton == MouseButtonState.Pressed)
			{
				Point mousePosition = e.GetPosition(dragSource);
				if ((Math.Abs(mousePosition.X - mouseClickPosition.X) > SystemParameters.MinimumHorizontalDragDistance) ||
					(Math.Abs(mousePosition.Y - mouseClickPosition.Y) > SystemParameters.MinimumVerticalDragDistance))
				{
					DataObject dragData = new DataObject(DataFormatName, dragSourceData);

					// Start dragging
					DragDropEffects finalDropEffect = DragDrop.DoDragDrop(dragSource, dragData, DragDropEffects.Move | DragDropEffects.Copy);
					
					// Reset
					dragSource = null;
					dragSourceData = null;
				}

			}

		}

Christian

Weeks of programming can save you hours of planning