Tout en utilisant le glisser-déposer, puis-je faire en sorte que Treeview développe le nœud sur lequel l’utilisateur survole?

En bref:

Existe-t-il une fonction intégrée dans .Net 2.0 pour développer TreeNode s en survolant une opération de glisser-déposer?

J’utilise C # dans Visual Studio 2005.

Plus en détail:

J’ai Treeview un contrôle Treeview avec une arborescence multi-niveaux et multinodée (pensez à un organigramme Treeview à une boîte de dialog de fichier / dossier) et je souhaite utiliser le glisser-déposer pour déplacer les nœuds dans l’arborescence.

Le code de glisser-déposer fonctionne bien et je peux déposer sur n’importe quel nœud visible, mais j’aimerais que mon contrôle se comporte comme l’explorateur Windows lors du déplacement de fichiers sur le volet de navigation. Plus précisément, j’aimerais que chaque dossier s’ouvre s’il est survolé pendant environ une seconde ou deux.

J’ai commencé à développer une solution utilisant Threading et une méthode Sleep , mais je rencontre des problèmes et je me demandais s’il y avait déjà quelque chose en place. Sinon, je vais m’attarder et apprendre à utiliser le threading (il est grand temps, mais j’étais en espérant faire sortir cette application rapidement)

Dois-je écrire mon propre code pour gérer le développement d’un TreeNode lorsqu’il est survolé en mode glisser-déposer?

Vous pouvez utiliser l’événement DragOver. il se déclenche de manière répétée pendant que vous faites glisser un object L’ouverture après un délai peut se faire très facilement avec deux variables supplémentaires qui notent le dernier object sous la souris et l’heure. Aucun thread ou autre astuce nécessaire (lastDragDestination et lastDragDestinationTime dans mon exemple)

De mon propre code:

 TreeNode lastDragDestination = null; DateTime lastDragDestinationTime; private void tvManager_DragOver(object sender, DragEventArgs e) { IconObject dragDropObject = null; TreeNode dragDropNode = null; //always disallow by default e.Effect = DragDropEffects.None; //make sure we have data to transfer if (e.Data.GetDataPresent(typeof(TreeNode))) { dragDropNode = (TreeNode)e.Data.GetData(typeof(TreeNode)); dragDropObject = (IconObject)dragDropNode.Tag; } else if (e.Data.GetDataPresent(typeof(ListViewItem))) { ListViewItem temp (ListViewItem)e.Data.GetData(typeof(ListViewItem)); dragDropObject = (IconObject)temp.Tag; } if (dragDropObject != null) { TreeNode destinationNode = null; //get current location Point pt = new Point(eX, eY); pt = tvManager.PointToClient(pt); destinationNode = tvManager.GetNodeAt(pt); if (destinationNode == null) { return; } //if we are on a new object, reset our timer //otherwise check to see if enough time has passed and expand the destination node if (destinationNode != lastDragDestination) { lastDragDestination = destinationNode; lastDragDestinationTime = DateTime.Now; } else { TimeSpan hoverTime = DateTime.Now.Subtract(lastDragDestinationTime); if (hoverTime.TotalSeconds > 2) { destinationNode.Expand(); } } } } 

MODIFIER

J’ai une nouvelle solution, un peu tirée par les cheveux, mais cela fonctionne … Elle utilise une classe DelayedAction pour gérer l’exécution différée d’une action sur le thread principal:

DelayedAction

 public class DelayedAction { private SynchronizationContext _syncContext; private Action _action; private int _delay; private Thread _thread; public DelayedAction(Action action) : this(action, 0) { } public DelayedAction(Action action, int delay) { _action = action; _delay = delay; _syncContext = SynchronizationContext.Current; } public void RunAfterDelay() { RunAfterDelay(_delay, default(T)); } public void RunAfterDelay(T param) { RunAfterDelay(_delay, param); } public void RunAfterDelay(int delay) { RunAfterDelay(delay, default(T)); } public void RunAfterDelay(int delay, T param) { Cancel(); InitThread(delay, param); _thread.Start(); } public void Cancel() { if (_thread != null && _thread.IsAlive) { _thread.Abort(); } _thread = null; } private void InitThread(int delay, T param) { ThreadStart ts = () => { Thread.Sleep(delay); _syncContext.Send( (state) => { _action((T)state); }, param); }; _thread = new Thread(ts); } } 

AutoExpandTreeView

 public class AutoExpandTreeView : TreeView { DelayedAction _expandNode; public AutoExpandTreeView() { _expandNode = new DelayedAction((node) => node.Expand(), 500); } private TreeNode _prevNode; protected override void OnDragOver(DragEventArgs e) { Point clientPos = PointToClient(new Point(eX, eY)); TreeViewHitTestInfo hti = HitTest(clientPos); if (hti.Node != null && hti.Node != _prevNode) { _prevNode = hti.Node; _expandNode.RunAfterDelay(hti.Node); } base.OnDragOver(e); } }