10
votes

La meilleure façon de filtrer les nœuds d'Aperview

Quel est le moyen le mieux / efficacement de filtrer arboresview nœuds?

Par exemple: j'ai tapé "abc" et seuls les nœuds contenus "abc" sont visibles. Ensuite, j'ai tapé "abcd" , et je devrais voir les seuls nœuds contenant "abcd" text. Et ainsi de suite, chaque fois que j'ai changé de critère de filtre, le contenu TreeView modifie également.

Des idées?


0 commentaires

4 Réponses :


10
votes

Si vous recherchez les meilleures performances, clonez l'arborescence, puis retirez tous les éléments de l'arbre cloné, puis remplacez simplement l'arborescence existante avec le cloné (et filtré).

Je garde aussi un arbre de support qui est toujours non filtré.

Cela fonctionne bien pour moi pour des arbres assez gros avec 1000 - 2000 nœuds.


7 commentaires

Je suis d'accord avec cette approche, il y a un modèle en rapport avec le motif de Memento.


Ce n'est pas joli, il aurait été tellement plus agréable d'avoir une propriété «visible» sur une treenode.


Je vais tester cette méthode. Merci pour le conseil. Je prévois de mettre en œuvre cette fonctionnalité sur l'arborescence avec des nœuds jusqu'à 10-20K ...


+1 Quel comportement avez-vous mis en œuvre pour la situation où un parent ne correspond pas à correspond aux critères, mais un enfant de ce parent fait correspond aux critères?


@John: Je n'ai pas ce scénario :) Le filtre ne part que des feuilles.


@Murat: Peut-être que TreeViewAdv serait un meilleur choix.


@Murat (ou LEPPIE) RE: Clonage de l'arborescence - Est-ce que le TreenOdecollection ? Un clonage récursif de chaque Treenode à travers ses nœuds enfants? Pas l'ensemble Treeview contrôle, non?



-1
votes

Si vous bouclez de la feuille au parent, vous pouvez trouver ces nœuds racines qui ne contiennent aucune correspondance de la chaîne dans ses feuilles.


1 commentaires

La question ne concerne pas la traversée des arbres ni la manière de faire correspondre une chaîne, il s'agit de filtrer / restaurer l'état d'une arborescence de manière efficace.



1
votes

i hériter d'arbres pour filtrer (uniquement pour le premier niveau, je travaille dessus):

public partial class winTree : TreeView
{
    private NodesCollection allNodes = new NodesCollection();

    [ReadOnly(true)]
    public new NodesCollection Nodes { get { return allNodes; } }

    private string filtro = string.Empty;
    public String Filtro
    {
        get { return filtro; }
        set { filtro = value; filtrarNodos(); }
    }

    public winTree()
    {
        InitializeComponent();

        allNodes.NodeAdd += OnNodeAdd;
        allNodes.NodeRemove += OnNodeRemove;
        allNodes.NodesClear += OnNodesClear;
    }


    private void OnNodeAdd(object sender, EventArgs e)
    {
        TreeNode n = (TreeNode)sender;

        if (passFilter(n))
        {
            base.Nodes.Add(n);
        }
    }

    private void OnNodeRemove(object sender, EventArgs e)
    {
        base.Nodes.Remove((TreeNode)sender);
    }

    private void OnNodesClear(object sender, EventArgs e)
    {
        base.Nodes.Clear();
    }


    private void filtrarNodos()
    {
        this.BeginUpdate();

        base.Nodes.Clear();

        foreach(TreeNode n in this.Nodes)
        {
            if (passFilter(n))
            {
                base.Nodes.Add(n);
            }
        }

        this.EndUpdate();
    }

    private bool passFilter(TreeNode nodo)
    {
        if (string.IsNullOrWhiteSpace(filtro))
        {
            return true;
        }
        else
        {
            return nodo.Text.ToLower().Contains(filtro.ToLower());
        }
    }
}

public class NodesCollection : IList<TreeNode>
{
    private List<TreeNode> nodos = new List<TreeNode>();

    public event EventHandler NodeAdd;
    public event EventHandler NodeRemove;
    public event EventHandler NodesClear;

    private void OnNodeAdd(TreeNode nodo)
    {
        if (NodeAdd != null)
        {
            NodeAdd(nodo, EventArgs.Empty);
        }
    }

    private void OnNodeRemove(TreeNode nodo)
    {
        if (NodeRemove != null)
        {
            NodeRemove(nodo, EventArgs.Empty);
        }
    }

    private void OnNodesClear()
    {
        if (NodeRemove != null)
        {
            NodesClear(this, EventArgs.Empty);
        }
    }


    #region IList<TreeNode>

        public int IndexOf(TreeNode item)
        {
            return nodos.IndexOf(item);

            OnNodeAdd(item);
        }

        public void Insert(int index, TreeNode item)
        {
            nodos.Insert(index, item);

            OnNodeAdd(item);
        }

        public void RemoveAt(int index)
        {
            TreeNode nodo = nodos[index];

            nodos.RemoveAt(index);

            OnNodeRemove(nodo);
        }

        public TreeNode this[int index]
        {
            get
            {
                return nodos[index];
            }
            set
            {
                OnNodeRemove(nodos[index]);
                nodos[index] = value;
                OnNodeAdd(nodos[index]);
            }
        }

        public void Add(TreeNode item)
        {
            nodos.Add(item);

            OnNodeAdd(item);
        }

        public void Clear()
        {
            nodos.Clear();

            OnNodesClear();
        }

        public bool Contains(TreeNode item)
        {
            return nodos.Contains(item);
        }

        public void CopyTo(TreeNode[] array, int arrayIndex)
        {
            nodos.CopyTo(array, arrayIndex);
        }

        public int Count
        {
            get { return nodos.Count(); }
        }

        public bool IsReadOnly
        {
            get { return true; }
        }

        public bool Remove(TreeNode item)
        {
            bool res = nodos.Remove(item);

            if (res)
            {
                OnNodeRemove(item);
            }

            return res;
        }

        public IEnumerator<TreeNode> GetEnumerator()
        {
            return nodos.GetEnumerator();
        }

        IEnumerator IEnumerable.GetEnumerator()
        {
            return nodos.GetEnumerator();
        }

    #endregion
}


0 commentaires

0
votes

J'aimerais offrir une meilleure solution, c'est que je ne veux pas dériver d'une nouvelle classe et moins de code impliqué.

Ma solution: p>

  • construire l'arborescence comme si cela ferait normalement le filtrage p> li>

  • Faites une sauvegarde de l'arborescence (code ci-dessous) (je ne le prends que si une recherche est faite, pas seulement au cas où) P> li>

  • désordre avec l'arbre enlever les nœuds et tout p> li>

  • Si vous devez réinitialiser l'arborescence comme initialement, appelez _backup.restore () p>

      using System.Linq;
      using System.Windows.Forms;
    
      public class TreeViewBackup : List<TreeViewBackup>
      {
          public TreeNode Parent { get; }
          public TreeNodeCollection Children { get; }
    
          public TreeViewBackup(TreeNodeCollection children, TreeNode parent = null)
          {
              Parent = parent;
              Children = children;
              AddRange(Children.Cast<TreeNode>().Select(child => new TreeViewBackup(child.Nodes, child)));
          }
    
          public void Restore()
          {
              Children.Clear();
              this.ForEach(clone => clone.Restore());
              Children.AddRange(this.Select(n => n.Parent).ToArray());
          }
      }
    
      public class Form1
      {
          public void Filter()
          {
             _backup = new TreeViewBackup(_treeView.Nodes);
             _treeView.BeginUpdate();
             MessWithMe();
             _treeView.EndUpdate();
          }
    
          public void Undo()
          {
             _treeView.BeginUpdate();
             _backup.Restore();
             _treeView.EndUpdate();
          }
      }
    


0 commentaires