Фильтрация дерева с помощью текстового поля в приложении winforms С#

У меня есть TreeView в моей winform С#. Я хотел бы иметь возможность добавить функцию поиска через окно поиска. В основном, поскольку пользователь вводит буквы (я угадываю событие _TextChanged), я показываю только узлы, которые содержат дочерние элементы с введенными буквами...

My TreeView содержит 53 родительских узла в общей сложности более 15000 узлов, поэтому мне нужно что-то немного результативное. Я создаю свой TreeView из csv, который загружаю в DataTable, а затем создаю запросы для получения родительских узлов с связанными дочерними узлами...

UPDATE

У меня есть идея. Конечная цель заключается в том, что при двойном щелчке пользователя по дочернему элементу node он добавляется в списокView.

Я впервые применил эту функцию поиска в простом представлении списка, где я не разделял свои данные по категориям.

Моя идея в том, что как только пользователь начнет вводить текст, я отключу свое представление Tree и покажу вид списка...

Я попытаюсь реализовать и посмотреть, что он дает производительность мудрым... Любые критики по этой идее приветствуются.

Ответ 1

Наконец, это то, что я сделал, это соответствует моим требованиям. Сначала я делаю копию своего TreeView и сохраняю в fieldsTreeCache. Затем я очищаю поля Tree. Затем я просматриваю кеш и добавляю любой node содержащий мой параметр поиска в поля Tree. Обратите внимание, что после поиска вы больше не показываете родительские узлы. Вы просто получаете все конечные узлы. Я сделал это, потому что, если бы у меня не было двух вариантов:

  • Разверните все родительские узлы, содержащие дочерние элементы, которые совпадают, но затем они были медленными, и у одного родителя могло быть 50 детей, что не очень визуально.
  • Не расширяйте родительские узлы, но затем вы получаете только категории, а не те узлы, которые вы ищете.

    void fieldFilterTxtBx_TextChanged(object sender, EventArgs e)
    {
        //blocks repainting tree till all objects loaded
        this.fieldsTree.BeginUpdate();
        this.fieldsTree.Nodes.Clear();
        if (this.fieldFilterTxtBx.Text != string.Empty)
        {
            foreach (TreeNode _parentNode in _fieldsTreeCache.Nodes)
            {
                foreach (TreeNode _childNode in _parentNode.Nodes)
                {
                    if (_childNode.Text.StartsWith(this.fieldFilterTxtBx.Text))
                    {
                        this.fieldsTree.Nodes.Add((TreeNode)_childNode.Clone());
                    }
                }
            }
        }
        else
        {
            foreach (TreeNode _node in this._fieldsTreeCache.Nodes)
            {
                fieldsTree.Nodes.Add((TreeNode)_node.Clone());
            }
        }
        //enables redrawing tree after all objects have been added
        this.fieldsTree.EndUpdate();
    }
    

Ответ 2

Здесь небольшой простой пример (с кодом из msdn) заключается в том, что очень простой способ отфильтровать показания TreeView node.

winforms в древовидном представлении вы можете добавлять или удалять TreeNode.

Поиск узлов может быть улучшен, если узлы хранятся с их данными в словаре (с уникальным ключом).

using System.Collections;
using System.Windows.Forms;

namespace FilterWinFormsTreeview
{
  // The basic Customer class.
  public class Customer : System.Object
  {
    private string custName = "";
    protected ArrayList custOrders = new ArrayList();

    public Customer(string customername) {
      this.custName = customername;
    }

    public string CustomerName {
      get { return this.custName; }
      set { this.custName = value; }
    }

    public ArrayList CustomerOrders {
      get { return this.custOrders; }
    }
  }

  // End Customer class 

  // The basic customer Order class.
  public class Order : System.Object
  {
    private string ordID = "";

    public Order(string orderid) {
      this.ordID = orderid;
    }

    public string OrderID {
      get { return this.ordID; }
      set { this.ordID = value; }
    }
  }

  // End Order class

  public static class TreeViewHelper
  {
    // Create a new ArrayList to hold the Customer objects.
    private static ArrayList customerArray = new ArrayList();

    public static void FilterTreeView(TreeView treeView1, string orderText) {
      if (string.IsNullOrEmpty(orderText)) {
        FillMyTreeView(treeView1);
      } else {
        // Display a wait cursor while the TreeNodes are being created.
        Cursor.Current = Cursors.WaitCursor;

        // Suppress repainting the TreeView until all the objects have been created.
        treeView1.BeginUpdate();

        foreach (TreeNode customerNode in treeView1.Nodes) {
          var customer = customerNode.Tag as Customer;
          if (customer != null) {
            customerNode.Nodes.Clear();
            // Add a child treenode for each Order object in the current Customer object.
            foreach (Order order in customer.CustomerOrders) {
              if (order.OrderID.Contains(orderText)) {
                var orderNode = new TreeNode(customer.CustomerName + "." + order.OrderID);
                customerNode.Nodes.Add(orderNode);
              }
            }
          }
        }

        // Reset the cursor to the default for all controls.
        Cursor.Current = Cursors.Default;

        // Begin repainting the TreeView.
        treeView1.EndUpdate();
      }
    }

    public static void FillMyTreeView(TreeView treeView1) {
      // Add customers to the ArrayList of Customer objects.
      if (customerArray.Count <= 0) {
        for (int x = 0; x < 1000; x++) {
          customerArray.Add(new Customer("Customer" + x.ToString()));
        }

        // Add orders to each Customer object in the ArrayList.
        foreach (Customer customer1 in customerArray) {
          for (int y = 0; y < 15; y++) {
            customer1.CustomerOrders.Add(new Order("Order" + y.ToString()));
          }
        }
      }

      // Display a wait cursor while the TreeNodes are being created.
      Cursor.Current = Cursors.WaitCursor;

      // Suppress repainting the TreeView until all the objects have been created.
      treeView1.BeginUpdate();

      // Clear the TreeView each time the method is called.
      treeView1.Nodes.Clear();

      // Add a root TreeNode for each Customer object in the ArrayList.
      foreach (Customer customer2 in customerArray) {
        var customerNode = new TreeNode(customer2.CustomerName);
        customerNode.Tag = customer2;
        treeView1.Nodes.Add(customerNode);

        // Add a child treenode for each Order object in the current Customer object.
        foreach (Order order1 in customer2.CustomerOrders) {
          var orderNode = new TreeNode(customer2.CustomerName + "." + order1.OrderID);
          customerNode.Nodes.Add(orderNode);
        }
      }

      // Reset the cursor to the default for all controls.
      Cursor.Current = Cursors.Default;

      // Begin repainting the TreeView.
      treeView1.EndUpdate();
    }
  }
}

Ответ 3

  • Каждый node в TreeView имеет свойства Expanded и IsVisible. Количество предметов, которые видны одновременно, ограничено (TreeView.VisibleCount). Основываясь на этой информации, вы можете значительно сократить количество узлов, которые будут исследовать.

  • При сканировании node и его дочерних узлов вы можете прервать рекурсию, когда вы найдете первое совпадение внутри свернутого node, таким образом вы уже знаете, что у него есть хотя бы один ребенок и все равно будет видимым.

  • Выполните фильтрацию асинхронно. (например, используйте new Task()). Начните первую задачу после того, как было напечатано минимальное количество символов (скажем, 3). Каждый следующий напечатанный char должен отменить запущенную задачу и запустить новую.