Фильтрация дерева в текстовом поле в приложении winforms C # - PullRequest
11 голосов
/ 24 ноября 2011

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

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

UPDATE

У меня есть идея. Конечная цель состоит в том, что когда пользователь дважды щелкает по дочернему узлу, он добавляется в listView.

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

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

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

Ответы [ 3 ]

9 голосов
/ 25 ноября 2011

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

  • Разверните все родительские узлы, содержащие совпадающие дочерние элементы, но затем это было медленным, и у одного из родителей могло бы быть 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 голосов
/ 25 ноября 2011

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

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();
    }
  }
}
0 голосов
/ 24 ноября 2011
  1. Каждый узел в TreeView имеет свойства Expanded и IsVisible.Количество одновременно видимых предметов ограничено (TreeView.VisibleCount).Основываясь на этой информации, вы можете значительно сократить количество проверяемых узлов.

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

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...