简体   繁体   English

使用C#winforms应用程序中的文本框过滤树视图

[英]Filter a Treeview with a Textbox in a C# winforms app

I have a TreeView in my a C# winform. 我在C#winform中有一个TreeView。 I would like to be able to add a search functionality through a search box. 我希望能够通过搜索框添加搜索功能。 Basically as the user types in letters (I'm guessing on the _TextChanged event), I show only the nodes that contain childnodes with the inputed letters... 基本上当用户输入字母时(我猜测_TextChanged事件),我只显示包含带有输入字母的子节点的节点...

My TreeView contains 53 parent nodes for a total of over 15000 Nodes so I need something a bit performant. 我的TreeView包含53个父节点,总共超过15000个节点,因此我需要一些高性能的东西。 I build my TreeView from a csv that I load into a DataTable and then make queries on to get the Parent nodes with associated child nodes... 我从一个csv构建我的TreeView,我将其加载到DataTable中,然后进行查询以获取具有关联子节点的Parent节点...

UPDATE UPDATE

I have an idea. 我有个主意。 The final aim is that when a user doubleclicks on a child node it gets added to a listView. 最终目标是当用户双击子节点时,它会被添加到listView中。

I had first implemented this search function in a simple list view where I didn't separate my data into categories. 我首先在一个简单的列表视图中实现了这个搜索功能,我没有将我的数据分成几类。

My idea is that once the user starts typing in things, I turn off my Tree view and show the list view instead... 我的想法是,一旦用户开始输入内容,我就会关闭我的树视图并显示列表视图......

I'll try and implement and see what it gives performance wise... Any critics on this idea are welcome. 我会尝试并实施,看看它给出的表现明智......任何关于这个想法的评论家都是受欢迎的。

Finally this is what I did, it suits my requirements. 最后这就是我所做的,它符合我的要求。 I first make a copy of my TreeView and store into fieldsTreeCache. 我首先制作TreeView的副本并存储到fieldsTreeCache中。 I then clear the fieldsTree. 然后我清除了字段树。 I then search through the cache and add any node containing my search parameter to the fieldsTree. 然后,我搜索缓存并将包含我的搜索参数的任何节点添加到fieldsTree。 Note here that once you search, you no longer have the parent nodes that show. 请注意,一旦搜索,您将不再拥有显示的父节点。 You just get all of the end nodes. 你只需要获得所有的终端节点。 I did this because if not I had 2 choices: 我这样做是因为如果没有,我有两个选择:

  • Expand all the parent nodes containing childs that match but then it was slow and one parent might have 50 children which isn't great visually. 展开包含匹配的子节点的所有父节点,但之后它很慢,并且一个父节点可能有50个子节点在视觉上不是很好。
  • Not expand the parent nodes but then you just get the categories and not the children nodes that you're searching for. 不扩展父节点,但是您只需获取类别而不是您要搜索的子节点。

     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(); } 

Here's a small simple example (with code from msdn) is that a very simple way to filter out the TreeView node displays. 这是一个简单的小例子(来自msdn的代码)是一种过滤TreeView节点显示的非常简单的方法。

winforms in a tree view you can only add or remove TreeNode. 在树视图中的winforms只能添加或删除TreeNode。

The search for the nodes can still be improved if the nodes are stored with their data into a dictionary (with a unique key). 如果将节点与其数据一起存储到字典中(使用唯一键),则仍可以改进对节点的搜索。

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();
    }
  }
}
  1. Every node in TreeView has Expanded and IsVisible properties. TreeView每个节点都具有ExpandedIsVisible属性。 The number of items which are visible at the same time is limited ( TreeView.VisibleCount ). 同时可见的项目数量是有限的( TreeView.VisibleCount )。 Based on this information you can reduce the number of nodes to probe dramatically. 根据此信息,您可以显着减少要探测的节点数。

  2. When scanning the node and it's child nodes you can abort recursion as you find the first match inside collapsed node, thus you already know it has at least one child and will be visible anyway. 当扫描节点及其子节点时,您可以在折叠节点内找到第一个匹配时中止递归,因此您已经知道它至少有一个子节点并且无论如何都会可见。

  3. Perform filtering asynchronously. 异步执行过滤。 (use new Task() for instance) Start the first task after minimal number of chars was typed (let's say 3). (例如,使用new Task() )在输入最少数量的字符后开始第一个任务(假设为3)。 Every next typed char must cancel the running task and start the new one. 每个下一个键入的char都必须取消正在运行的任务并启动新任务。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM