Autor |
Beitrag |
lapadula
Beiträge: 180
Erhaltene Danke: 10
|
Verfasst: Do 08.06.17 21:17
Hallo, weiss jemand wie man die childnodes innerhalb eines Knotens mit der Maus verschieben kann, sprich die Pätze sollen getauscht werden?
Hab mich ein wenig umgeguckt aber die meisten packen die childnodes in ein anders childnode.
z. B.
Automarken
- Audi
- BMW
- Mercedes
Mercedes soll nun an erster Stelle stehen, dies möchte ich aber mit der Maus verschieben.
Mfg
Zuletzt bearbeitet von lapadula am Fr 09.06.17 15:01, insgesamt 1-mal bearbeitet
|
|
Ralf Jansen
Beiträge: 4705
Erhaltene Danke: 991
VS2010 Pro, VS2012 Pro, VS2013 Pro, VS2015 Pro, Delphi 7 Pro
|
Verfasst: Do 08.06.17 23:18
Wenn du dir das angesehen hast weißt du ja ungefähr wie man das Drag&Drop startet.
Um die Reihenfolge der ChildNodes zu ändern mußt du den gedragten Node beim droppen aus der Liste der Childnodes entfernen und wieder in der Liste einfügen und zwar mit dem Index an der der Stelle an der du einfügen willst
C#-Quelltext 1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20:
| private void meinLieberTreeView_DragDrop(object sender, DragEventArgs e) { var sourceNode = e.Data.GetData(typeof(TreeNode)) as TreeNode; if (sourceNode == null) return;
var pt = ((TreeView)sender).PointToClient(new Point(e.X, e.Y)); var targetNode = ((TreeView)sender).GetNodeAt(pt); if (targetNode == null) return;
if (!sourceNode.Equals(targetNode) && targetNode.Parent == sourceNode.Parent) { targetNode.Parent.Nodes.RemoveAt(sourceNode.Index); targetNode.Parent.Nodes.Insert(targetNode.Index, sourceNode); } } |
Für diesen Beitrag haben gedankt: lapadula
|
|
lapadula
Beiträge: 180
Erhaltene Danke: 10
|
Verfasst: Fr 09.06.17 10:28
|
|
Ralf Jansen
Beiträge: 4705
Erhaltene Danke: 991
VS2010 Pro, VS2012 Pro, VS2013 Pro, VS2015 Pro, Delphi 7 Pro
|
Verfasst: Fr 09.06.17 10:38
Zitat: | Müsste es nicht so richtig sein, weil ich möchte doch das targetNode entfernen und den SourceNode dahin platzieren? |
Eigentlich nicht. Du möchtest einen Node an der Stelle des TargetNodes einfügen. Stell dir vor deine 3 ChildNodes haben vollgende Indexe
Quelltext
jetzt nimmst du den Node mit Index 3 (Mercedes) und droppst in auf den Node mit Index 1(Audi). Der Vorgang wäre
a.) Node 3(Mercedes) entfernen
b.) Und als Node 1 wieder einfügen.
Da es einen Node 1 (Audi) bereits gibt wird dessen Indes weitergeschoben und alle folgenden Nodes auch. So das du im Anschluss
Quelltext
hast.
Für diesen Beitrag haben gedankt: lapadula
|
|
lapadula
Beiträge: 180
Erhaltene Danke: 10
|
Verfasst: Fr 09.06.17 10:58
Ahso
Und wenn ich Mercedes mit Audi tauschen möchte, also
Mercedes
BMW
Audi
zu
Audi
BMW
Mercedes
ohne das sich der Index von BMW sich ändert und weitergeschoben wird.
|
|
Ralf Jansen
Beiträge: 4705
Erhaltene Danke: 991
VS2010 Pro, VS2012 Pro, VS2013 Pro, VS2015 Pro, Delphi 7 Pro
|
Verfasst: Fr 09.06.17 13:09
Oh, ich hatte verschieben verstanden nicht tauschen.
Remove Insert muß man einfach 2 mal machen. Die Reihenfolge könnte etwas difizil sein damit genau das Richtige rauskommt
Das will ich erstmal ausprobieren bevor ich das als Code zeige, ist mir aus dem lameng zu gefährlich
Für diesen Beitrag haben gedankt: lapadula
|
|
lapadula
Beiträge: 180
Erhaltene Danke: 10
|
Verfasst: Fr 09.06.17 14:48
Hab mich da wohl wieder undeutlich ausgedrückt, sorry. Das englische wort wäre swap, glaube ich.
Habe das nun soweit, dass die Nodes richtig sortiert in ein Array kommen aber dieses Array mit Nodes kann ich nicht ausgeben und ich weiss echt nicht warum.
Hier mein Code:
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: 21: 22: 23: 24: 25: 26: 27: 28: 29: 30: 31: 32: 33: 34: 35:
| if (!sourceNode.Equals(targetNode) && targetNode.Parent == sourceNode.Parent) { TreeNode[] newNodes = new TreeNode[sourceNode.Parent.Nodes.Count];
int targetIndex = targetNode.Index; int sourceIndex = sourceNode.Index;
for (int i = 0; i < sourceNode.Parent.Nodes.Count; i++) { if (i == targetIndex) { newNodes[i] = sourceNode.Parent.Nodes[sourceIndex]; } else if (i == sourceIndex) { newNodes[i] = sourceNode.Parent.Nodes[targetIndex]; } else { newNodes[i] = sourceNode.Parent.Nodes[i]; } }
sourceNode.Parent.Nodes.Clear();
foreach (TreeNode node in newNodes) { sourceNode.Parent.Nodes.Add(node); } } |
Wenn ich mein treeView direkt anspreche, dann klappt das zwar, allerdings verschwindet das Parent. Habe das im Code nochmal zusätzlich kommentiert
|
|
lapadula
Beiträge: 180
Erhaltene Danke: 10
|
Verfasst: Fr 09.06.17 15:39
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: 21: 22: 23: 24: 25: 26: 27: 28: 29: 30: 31: 32: 33: 34: 35:
| if (!sourceNode.Equals(targetNode) && targetNode.Parent == sourceNode.Parent) { TreeNode[] newNodes = new TreeNode[sourceNode.Parent.Nodes.Count];
TreeNode parentNode = sourceNode.Parent;
int targetIndex = targetNode.Index; int sourceIndex = sourceNode.Index;
for (int i = 0; i < sourceNode.Parent.Nodes.Count; i++) { if (i == targetIndex) { newNodes[i] = sourceNode.Parent.Nodes[sourceIndex]; } else if (i == sourceIndex) { newNodes[i] = sourceNode.Parent.Nodes[targetIndex]; } else { newNodes[i] = sourceNode.Parent.Nodes[i]; } }
treeView2.Nodes.Clear(); treeView2.Nodes.Add(parentNode);
foreach (TreeNode node in newNodes) { treeView2.Nodes[0].Nodes.Add(node); } treeView2.ExpandAll(); } |
Ich versuche nun alles zu clearen, vorher merke ich mir das Parent und möchte es dann wieder hinzufügen + die ganzen childnodes.
Leider bleibt die Reihenfolge gleich. Außer ich füge Parent.Text hinzu, oder "treeView".Nodes.Add("Parent"), dann macht er alles richtig.
Du bist meine letzte Hoffnung Ralf
|
|
Ralf Jansen
Beiträge: 4705
Erhaltene Danke: 991
VS2010 Pro, VS2012 Pro, VS2013 Pro, VS2015 Pro, Delphi 7 Pro
|
Verfasst: Fr 09.06.17 19:29
Das Ganze jetzt mit tauschen anstatt verschieben. Habe die Funktionalität zum tauschen, da wie angenommen etwas komplexer, in eine Extensionmethod ausgelagert.
C#-Quelltext 1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14:
| private void meinLieberTreeView_DragDrop(object sender, DragEventArgs e) { var sourceNode = e.Data.GetData(typeof(TreeNode)) as TreeNode; if (sourceNode == null) return;
var pt = ((TreeView)sender).PointToClient(new Point(e.X, e.Y)); var targetNode = ((TreeView)sender).GetNodeAt(pt); if (targetNode == null) return;
if (!sourceNode.Equals(targetNode) && targetNode.Parent == sourceNode.Parent) targetNode.Parent.SwapNodes(sourceNode, targetNode); } |
und hier die Klasse mit der Extensionmethod
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: 21: 22: 23: 24: 25: 26: 27: 28: 29: 30: 31: 32: 33:
| public static class TreeViewExtensions { public static void SwapNodes(this TreeNode parent, TreeNode first, TreeNode second) { if (parent == null) throw new ArgumentNullException(nameof(parent)); if (first == null) throw new ArgumentNullException(nameof(first)); if (second == null) throw new ArgumentNullException(nameof(second)); if (!parent.Nodes.Contains(first) || !parent.Nodes.Contains(second)) throw new InvalidOperationException("To swap, both nodes have to be in the parent collection.");
if (first.Index > second.Index) Swap(ref first, ref second);
int firstIndex = first.Index; int secondIndex = second.Index;
first.Remove(); second.Remove();
parent.Nodes.Insert(firstIndex, second); parent.Nodes.Insert(secondIndex, first); }
private static void Swap<T>(ref T first, ref T second) { T temp = first; first = second; second = temp; } } |
Edit : Text der Fehlermeldung geändert.
Zuletzt bearbeitet von Ralf Jansen am Sa 10.06.17 14:46, insgesamt 2-mal bearbeitet
Für diesen Beitrag haben gedankt: lapadula
|
|
Frühlingsrolle
Ehemaliges Mitglied
Erhaltene Danke: 1
|
Verfasst: Fr 09.06.17 20:25
- Nachträglich durch die Entwickler-Ecke gelöscht -
Für diesen Beitrag haben gedankt: lapadula, Ralf Jansen
|
|
lapadula
Beiträge: 180
Erhaltene Danke: 10
|
Verfasst: Sa 10.06.17 10:38
Ohje, vielen Dank dafür!
Ich teste es im Laufe des Tages mal.
Bin bei meiner Lösung nicht weitergekommen.
Sowas müsste die Treeview eig standardmäßig können.
|
|
Ralf Jansen
Beiträge: 4705
Erhaltene Danke: 991
VS2010 Pro, VS2012 Pro, VS2013 Pro, VS2015 Pro, Delphi 7 Pro
|
Verfasst: Sa 10.06.17 12:11
Zitat: | Bin bei meiner Lösung nicht weitergekommen. |
In deiner gezeigten Lösung schreib mal hinter
C#-Quelltext 1:
| treeView1.Nodes.Clear(); |
auch
C#-Quelltext 1:
| parentNode.Nodes.Clear(); |
Du dachtest wohl das ein Clear am Treeview alle Nodes löscht aber übersehen das an dem gemerkten ParentNode den du wieder anhängst auch weiterhin ChildNodes hängen.
Der
C#-Quelltext 1:
| treeView1.Nodes.Add(parentNode); |
fügst alle Nodes wieder hinzu weil die ja alle noch am Parentnode hängen. Clear+Add hat dann nichts am Inhalt des TreeView geändert falls der ParentNode der einzige Node in der ersten Ebene des TreeViews war. Danach weitere sortierte Nodes an den Parentnode hängen geht nicht weil die ja immer noch dran hängen und das ein Node zweimal im TreeView hängt ist logischerweise nicht erlaubt
Wenn du zu Übungszwecken deine Lösung zum fliegen bringen willst fehlt nicht viel. Du solltest versuchen den TreeView selbst aus der Logik herauszuhalten und dich nur auf die Nodes (insbesondere ParentNode anstatt TreeView) zu beziehen. Ist eigentlich einfacher und die Lösung ist generischer da egal ist wo genau sich der relevante Node im Baum steckt. Deine Lösung funktioniert nur (mit kleiner Korrektur) wenn der ParentNode auch der erste (einzige) Node in der Root des TreeViews ist.
Für diesen Beitrag haben gedankt: lapadula
|
|
lapadula
Beiträge: 180
Erhaltene Danke: 10
|
Verfasst: So 11.06.17 14:55
Danke für die Erklärung und nun funktioniert auch meine Lösung (nur wie du sagst, wenn es nur ein Parent gibt)
|
|