none
TreeView Node Drag&Drop RRS feed

  • Frage

  • Hallo,

    ich möchte in einem TreeView einen Node via Drag&Drop auf einen anderen Node im gleichen TreeView schieben. Also man zieht einen Node über andere und bekommt dann angezeigt auf welchen Nodes der Drop erlaubt ist. Und genau das ist mein Problem. Da es nur ein ItemDrag und kein ItemDragEnter oder ähnliches gibt und dann auch noch während dem aufrufen von DoDragDrop() kein NodeMouseHover Event mehr gefeuert wird kann ich nicht anzeigen das manche Nodes kein Drop erlauben.

    Gibt es da eine einfachere Lösung oder irgendwas was mir weiter Hilft?

    Danke und Grüße

    Donnerstag, 19. Januar 2012 12:48

Antworten

  • Hallo Fleit,
     
    du verwendest dafür das Event DragOver im TreeView.
    Dort kannst du mit folgendem Code die aktuelle Node feststellen:
    Auszug:
    Point pt = tvw.PointToClient(new Point(e.X, e.Y));
    var targetNode = tvwAblage.GetNodeAt(pt);
    if (targetNode != null)
    {
     ...
    

    Über den Parameter e.Effect gibst du dann an ob ein Drop möglich ist usw.
    Daniel
    Donnerstag, 19. Januar 2012 13:39

Alle Antworten

  • Hallo Fleit,
     
    du verwendest dafür das Event DragOver im TreeView.
    Dort kannst du mit folgendem Code die aktuelle Node feststellen:
    Auszug:
    Point pt = tvw.PointToClient(new Point(e.X, e.Y));
    var targetNode = tvwAblage.GetNodeAt(pt);
    if (targetNode != null)
    {
     ...
    

    Über den Parameter e.Effect gibst du dann an ob ein Drop möglich ist usw.
    Daniel
    Donnerstag, 19. Januar 2012 13:39
  • Hallo Fleit,

    Ich gehe davon aus, dass die Antwort Dir weitergeholfen hat.
    Solltest Du noch "Rückfragen" dazu haben, so gib uns bitte Bescheid.

    Grüße,
    Robert


    Robert Breitenhofer, MICROSOFT  Twitter Facebook
    Bitte haben Sie Verständnis dafür, dass im Rahmen dieses Forums, welches auf dem Community-Prinzip „Entwickler helfen Entwickler“ beruht, kein technischer Support geleistet werden kann oder sonst welche garantierten Maßnahmen seitens Microsoft zugesichert werden können.

    Mittwoch, 15. Februar 2012 08:13
    Moderator
  • Hallo

    ich habe ebenfalls ein Problem mit dem verschieben von Nodes in einem TreeView.

    ich möchte einen Knoten überhalb, unterhalb oder als Kind des Zielknotens einfügen. Das bestehende Problem dabei ist, dass ich bei jeder Mausbewegung im TreeView im DragOver Event überprüfe wo die Maus steht und auf Grund dessen eine Linie zeichne, die dem Benutzer anzeigt, wo der selektierte Knoten hinverschoben wird.

    [Bild nicht vorhanden, da die Fehlermeldung:

    "Im Textkörper dürfen keine Bilder oder Links enthalten sein, bis Ihr Konto von uns geprüft werden kann."

    erschin]

    Mein Code bisher ist folgender:

    using System;
    using System.Collections.Generic;
    using System.ComponentModel;
    using System.Data;
    using System.Drawing;
    using System.Linq;
    using System.Text;
    using System.Windows.Forms;
    
    namespace Versuche
    {
    	public partial class Form_TreeViewDragDrop : Form
    	{
    		//---------------------------------------------------------------------
    		// ENUMS
    		enum DragOverPosition
    		{
    			oben,
    			unten,
    			mittig,
    			none
    		}
    
    		//---------------------------------------------------------------------
    		// MEMBER VARIABLEN
    		/// <summary>
    		/// Speichert die Position des neuen Knoten, an welcher dieser beim Drop Event platziert werden soll.
    		/// </summary>
    		DragOverPosition m_ErstellpositionDesNeuenKnoten;
    
    		//---------------------------------------------------------------------
    		// KONSTRUKTOR
    		/// <summary>
    		/// Konstruktor
    		/// </summary>
    		public Form_TreeViewDragDrop()
    		{
    			InitializeComponent();
    
    			m_ErstellpositionDesNeuenKnoten = DragOverPosition.none;
    		}
    
    		//---------------------------------------------------------------------
    		// METHODEN
    		/// <summary>
    		/// Setzt die Bilder des TreeViews und Klappt alle Tests aus.
    		/// </summary>
    		/// <param name="sender"></param>
    		/// <param name="e"></param>
    		private void Form1_Load(object sender, EventArgs e)
    		{
    			// Set the TreeView control's default image and selected image indexes.
    			treeView1.ImageIndex = 0;
    			treeView1.SelectedImageIndex = 1;
    
    			treeView1.ExpandAll();
    		}
    		//---------------------------------------------------------------------
    		/// <summary>
    		/// Sorgt dafür, dass bereits beim Maus Hinunterklicken ein Knoten selektiert wird.
    		/// </summary>
    		/// <param name="sender"></param>
    		/// <param name="e"></param>
    		private void treeView1_MouseDown(object sender, MouseEventArgs e)
    		{
    			// Knoten ermitteln dem der gedragte Knoten hinzugefügt werden soll:
    			treeView1.SelectedNode = this.GetTreeNode();
    		}
    		//---------------------------------------------------------------------
    		/// <summary>
    		/// Beginnt den DragDrop-Vorgang
    		/// </summary>
    		/// <param name="sender"></param>
    		/// <param name="e"></param>
    		private void treeView1_ItemDrag(object sender, ItemDragEventArgs e)
    		{
    			// Zu verschiebenden Knoten wählen:
    			TreeNode sourceNode = (TreeNode)e.Item;
    
    			// DragDrop beginnen:
    			DoDragDrop(sourceNode, DragDropEffects.Move);
    		}
    		//---------------------------------------------------------------------
    		/// <summary>
    		/// Überprüft ob der DragDrop-Vorgang zugelassen wird.
    		/// Sollte kein Knoten ausgewählt worden sein, wird der
    		/// Vorgang nicht ausgeführt.
    		/// </summary>
    		/// <param name="sender"></param>
    		/// <param name="e"></param>
    		private void treeView1_DragEnter(object sender, DragEventArgs e)
    		{
    			// Nur TreeNodes werden zugelassen:
    			if (e.Data.GetDataPresent(typeof(TreeNode)))
    			{
    				e.Effect = DragDropEffects.Move;
    			}
    			else
    			{
    				e.Effect = DragDropEffects.None;
    			}
    		}
    		//---------------------------------------------------------------------
    		/// <summary>
    		/// Überprüft während der MausBewegung die Knoten, zu welchem der selektierte Knoten verschoben werden soll.
    		/// </summary>
    		/// <param name="sender"></param>
    		/// <param name="e"></param>
    		private void treeView1_DragOver(object sender, DragEventArgs e)
    		{
    			// Nur TreeNodes werden zugelassen:
    			if (e.Data.GetDataPresent(typeof(TreeNode)))
    			{
    				// Speichert den Knoten im TreeView auf welchem die Maus liegt.
    				TreeNode KnotenAnMausPosition = this.GetTreeNode();
    				
    				// Überprüfen, dass mit der Maus ein Knoten ausgewählt wurde und dieser nicht auf der Ebene 3 liegt, da diese die tiefste Ebene ist.
    				if (KnotenAnMausPosition != null)
    				{
    					Rectangle r = new Rectangle(0, KnotenAnMausPosition.Bounds.Top, treeView1.Width, 50);
    					treeView1.Invalidate(r);
    					treeView1.Update();
    
    					ErmittleCursorPosition(KnotenAnMausPosition);
    
    					e.Effect = DragDropEffects.Move;
    				}
    				else
    				{
    					e.Effect = DragDropEffects.None;
    				}
    			}
    			else
    			{
    				e.Effect = DragDropEffects.None;
    			}
    		}
    		//---------------------------------------------------------------------
    		/// <summary>
    		/// Sucht den Knoten im TreeView auf welchem der Mauszeiger liegt.
    		/// </summary>
    		/// <returns>TreeNode auf welchem der Mauszeiger liegt.</returns>
    		private TreeNode GetTreeNode()
    		{
    			// Knoten ermitteln dem der gedragte Knoten hinzugefügt werden soll:
    			Point p = treeView1.PointToClient(new Point(Cursor.Position.X, Cursor.Position.Y));
    			return treeView1.GetNodeAt(p);
    		}
    		//---------------------------------------------------------------------
    		/// <summary>
    		/// Erstellt eine Linie beim Überfahren der Knoten im TreeView, damit der Benutzer betrachten kann, wo sein Knoten am Ende sein wird.
    		/// </summary>
    		/// <returns>DragOverPosition damit beim Anlegen des Knotens die Position des neuen Knoten bestimmt werden kann.</returns>
    		private DragOverPosition ErmittleCursorPosition(TreeNode KnotenAnMausPosition)
    		{
    			// Graphics Objekt erstellen, welches verwendet wird um eine Linie zu zeichnen.
    			Graphics TreeGraphics = Graphics.FromHwnd(treeView1.Handle);
    
    			// Stift zum Zeichnen der Linie anlegen.
    			Pen LinePen = new Pen(Color.Black, 1.0F);
    			LinePen.DashStyle = System.Drawing.Drawing2D.DashStyle.Dot;
    
    			// Knoten ermitteln dem der gedragte Knoten hinzugefügt werden soll.
    			// wird nicht mit der Methode "GetTreeNode()" zugewiesen, weil der Point benötigt wird.
    			Point p = treeView1.PointToClient(new Point(Cursor.Position.X, Cursor.Position.Y));
    
    			if (p.Y < KnotenAnMausPosition.Bounds.Top + 5 && KnotenAnMausPosition.Level != 0)
    			{
    				// Die Position der Maus ist nahe dem oberen Rand des Knotens.
    				m_ErstellpositionDesNeuenKnoten = DragOverPosition.oben;
    				TreeGraphics.DrawLine(LinePen, 0, KnotenAnMausPosition.Bounds.Top, treeView1.Width, KnotenAnMausPosition.Bounds.Top);
    			}
    			if (p.Y > KnotenAnMausPosition.Bounds.Top + 5 && p.Y < KnotenAnMausPosition.Bounds.Bottom - 5 && KnotenAnMausPosition.Level != 3)
    			{
    				// Die Position der Maus ist in der Mitte des Knotens.
    				m_ErstellpositionDesNeuenKnoten = DragOverPosition.mittig;
    				TreeGraphics.DrawLine(LinePen, 200, KnotenAnMausPosition.Bounds.Top + (KnotenAnMausPosition.Bounds.Height / 2), treeView1.Width, KnotenAnMausPosition.Bounds.Top + (KnotenAnMausPosition.Bounds.Height / 2));
    			}
    			if (p.Y > KnotenAnMausPosition.Bounds.Bottom - 5 && KnotenAnMausPosition.Level != 0)
    			{
    				// Die Position der Maus ist nahe dem unteren Rand des Knotens.
    				m_ErstellpositionDesNeuenKnoten = DragOverPosition.unten;
    				TreeGraphics.DrawLine(LinePen, 0, KnotenAnMausPosition.Bounds.Bottom, treeView1.Width, KnotenAnMausPosition.Bounds.Bottom);
    			}
    
    			return m_ErstellpositionDesNeuenKnoten;
    		}
    		//---------------------------------------------------------------------
    		/// <summary>
    		/// Verschiebt den Knoten
    		/// </summary>
    		/// <param name="sender"></param>
    		/// <param name="e"></param>
    		private void treeView1_DragDrop(object sender, DragEventArgs e)
    		{
    			// Speichert den Knoten, der verschoben werden soll.
    			TreeNode nodeAusgewaehlterKnoten = e.Data.GetData(typeof(TreeNode)) as TreeNode;
    
    			// Knoten ermitteln welchem der gedragte Knoten hinzugefügt werden soll.
    			TreeNode KnotenAnMausPosition = this.GetTreeNode();
    
    			// Überprüfen ob die Maus auf einem Knoten liegt.
    			if (KnotenAnMausPosition != null)
    			{
    				// Kopiert den Selektierten Knoten.
    				TreeNode newNode = (TreeNode)nodeAusgewaehlterKnoten.Clone();
    								
    				if (m_ErstellpositionDesNeuenKnoten == DragOverPosition.oben || m_ErstellpositionDesNeuenKnoten == DragOverPosition.unten)
    				{
    					// Der selektierte Knoten soll oberhalb/ unterhalb des mit dem Mauszeiger ausgewählten Knotens eingefügt werden.
    					// Der Parent des ausgewählten Knoten bekommt ein weiteres Kind.
    					TreeNode parentNode = KnotenAnMausPosition.Parent;
    
    					// Hinzufügen des neuen Knotens.
    					parentNode.Nodes.Add(newNode);
    
    					int prevNode_nextNode_Index = 0;
    					TreeNode zuVerschiebenderKnoten = null;
    
    					if (m_ErstellpositionDesNeuenKnoten == DragOverPosition.oben)
    					{
    						// Den eingefügten Knoten um eins nach oben verschieben, damit er über dem Zielknoten liegt.
    						prevNode_nextNode_Index = newNode.PrevNode.Index;
    						if (prevNode_nextNode_Index > KnotenAnMausPosition.Index)
    						{
    							prevNode_nextNode_Index = KnotenAnMausPosition.Index;
    						}
    						zuVerschiebenderKnoten = (TreeNode)newNode.Clone();
    					}
    					else
    					{
    						// Den eingefügten Knoten um eins nach unten verschieben, damit er unter dem Zielknoten liegt.
    						prevNode_nextNode_Index = KnotenAnMausPosition.NextNode.Index;
    						if (prevNode_nextNode_Index < KnotenAnMausPosition.Index)
    						{
    							prevNode_nextNode_Index = KnotenAnMausPosition.Index;
    						}
    						zuVerschiebenderKnoten = (TreeNode)newNode.Clone();
    					}
    					// Fügt den neuen Knoten an der alten Position ein.
    					newNode.Parent.Nodes.Insert(prevNode_nextNode_Index, zuVerschiebenderKnoten);
    					// Entfernt den Knoten an der angegebenen Index Position
    					newNode.Remove();
    					newNode = zuVerschiebenderKnoten;
    				}
    				else if (m_ErstellpositionDesNeuenKnoten == DragOverPosition.mittig)
    				{
    					// Der selektierte Knoten soll innerhalb des mit dem Mauszeiger ausgewählten Knotens eingefügt werden.
    					// Hinzufügen des neuen Knotens:
    					KnotenAnMausPosition.Nodes.Add(newNode);
    				}
    
    				// Hat der Elternknoten des selektierten Knotens noch weitere Kinder? Falls nicht kann der Parent Knoten entfernt werden.
    				EntferneKnotenWelcherVerschobenWurde(nodeAusgewaehlterKnoten);
    
    				treeView1.ExpandAll();
    				treeView1.SelectedNode = newNode;
    			}
    		}
    		//---------------------------------------------------------------------
    		/// <summary>
    		/// Sorgt dafür dass der Knoten, welcher verschoben wurde entfernt wird und überprüft die Eltern des Knotens auf Kinder.
    		/// </summary>
    		/// <param name="nodeAusgewaehlterKnoten"></param>
    		private void EntferneKnotenWelcherVerschobenWurde(TreeNode nodeAusgewaehlterKnoten)
    		{
    			// Überprüfe, ob die Eltern des selektierten Knoten noch Kinder besitzen.
    			if (nodeAusgewaehlterKnoten.Parent.Level != 0 && nodeAusgewaehlterKnoten.Parent.GetNodeCount(false) == 1)
    			{
    				DialogResult WirklichEntfernen = MessageBox.Show(string.Format("Es wurde festgestellt, dass der Knoten \"{0}\" nach dem Verschieben keine Kinder mehr besitzt. Möchten Sie diesen entfernen?", nodeAusgewaehlterKnoten.Parent.Text), this.ProductName, MessageBoxButtons.YesNo, MessageBoxIcon.Question);
    				if (WirklichEntfernen == System.Windows.Forms.DialogResult.Yes)
    				{
    					if (nodeAusgewaehlterKnoten.Parent.Parent.Level != 0 && nodeAusgewaehlterKnoten.Parent.Parent.GetNodeCount(true) == 2)
    					{
    						nodeAusgewaehlterKnoten = nodeAusgewaehlterKnoten.Parent.Parent;
    					}
    					else
    					{
    						nodeAusgewaehlterKnoten = nodeAusgewaehlterKnoten.Parent;
    					}
    				}
    			}
    			// Entferne Selektierten Knoten
    			nodeAusgewaehlterKnoten.Remove();			
    		}
    	}
    }

    Was mache ich falsch, bzw. was kann ich verbessern, dass der TreeView nicht mehr flackert?

    Vielen Dank

    Michael Kress

    Freitag, 25. Oktober 2013 06:38