Meilleure façon de valider les opérations de glisser / déposer pour un TreeView en C #
-
01-07-2019 - |
Question
Je souhaite vérifier un glisser & amp; l'opération de largage est autorisée. Un élément valide peut provenir d'un autre de nos "contrôles", ou en interne à partir de l'arborescence personnalisée. Actuellement, j'ai ceci:
bool CanDrop(DragEventArgs e)
{
bool allow = false;
Point point = tree.PointToClient(new Point(e.X, e.Y));
TreeNode target = tree.GetNodeAt(point);
if (target != null)
{
if (CanWrite(target)) //user permissions
{
if (e.Data.GetData(typeof(DataInfoObject)) != null) //from internal application
{
DataInfoObject info = (DataInfoObject)e.Data.GetData(typeof(DataInfoObject));
DragDataCollection data = info.GetData(typeof(DragDataCollection)) as DragDataCollection;
if (data != null)
{
allow = true;
}
}
else if (tree.SelectedNode.Tag.GetType() != typeof(TreeRow)) //node belongs to this & not a root node
{
if (TargetExistsInNode(tree.SelectedNode, target) == false)
{
if (e.Effect == DragDropEffects.Copy)
{
allow = true;
}
else if (e.Effect == DragDropEffects.Move)
{
allow = true;
}
}
}
}
}
return allow;
}
J'ai déplacé tout le code de vérification sur cette méthode pour essayer d'améliorer les choses, mais pour moi, c'est toujours horrible!
Tant de logique et tant de choses à faire que l’arborescence ferait elle-même (par exemple, "TargetExistsInNode" vérifie si le noeud déplacé est déplacé vers l’un de ses enfants).
Quel est le meilleur moyen de valider une entrée dans un contrôle?
La solution
J'utilise la propriété TreeNode.Tag pour stocker un petit "contrôleur". objets qui constitue la logique. Exemple:
class TreeNodeController {
Entity data;
virtual bool IsReadOnly { get; }
virtual bool CanDrop(TreeNodeController source, DragDropEffects effect);
virtual bool CanDrop(DataInfoObject info, DragDropEffects effect);
virtual bool CanRename();
}
class ParentNodeController : TreeNodeController {
override bool IsReadOnly { get { return data.IsReadOnly; } }
override bool CanDrop(TreeNodeController source, DragDropEffect effect) {
return !IsReadOnly && !data.IsChildOf(source.data) && effect == DragDropEffect.Move;
}
virtual bool CanDrop(DataInfoObject info, DragDropEffects effect) {
return info.DragDataCollection != null;
}
override bool CanRename() {
return !data.IsReadOnly && data.HasName;
}
}
class LeafNodeController : TreeNodeController {
override bool CanDrop(TreeNodeController source, DragDropEffect effect) {
return false;
}
}
Ensuite, mon CanDrop serait quelque chose comme:
bool CanDrop(DragDropEventArgs args) {
Point point = tree.PointToClient(new Point(e.X, e.Y));
TreeNode target = tree.GetNodeAt(point);
TreeNodeController targetController = target.Tag as TreeNodeController;
DataInfoObject info = args.GetData(typeof(DataInfoObject)) as DataInfoObject;
TreeNodeController sourceController = args.GetData(typeof(TreeNodeController)) as TreeNodeController;
if (info != null) return targetController.CanDrop(info, e.Effect);
if (sourceController != null) return targetController.CanDrop(sourceController, e.Effect);
return false;
}
Maintenant, pour chaque classe d'objets que j'ajoute à l'arbre, je peux spécialiser le comportement en choisissant le TreeNodeController à placer dans l'objet Tag.
Autres conseils
Vous ne répondez pas strictement à votre question, mais j'ai détecté un bogue dans votre code.
DragDropEffects
a l'attribut flags défini afin que vous puissiez obtenir e.Effect
comme étant une combinaison bitwise de copier / déplacer. Dans ce cas, votre code renverrait incorrectement false.