none
C#:Treeview - организовать поиск RRS feed

  • Вопрос

  • Огромное спасибо Malobukv за вашу помощь. 

    Что ещё хотелось бы узнать как лучше организовать поиск по табельному и Фио сотрудника, которые будут вводиться в textbox?

    После того как  нашёл необходимого сотрудника по событию afterselect должна появляться новая форма, привязанная именно для этого сотрудника. Так вот вопрос каким образом мне  это оптимально сделать? 

    27 марта 2012 г. 21:50

Ответы

  • > организовать поиск по табельному и Фио сотрудника, которые будут вводиться в textbox?


    в предыдущем примере: public Form1() {...} -- замените следующим кодом:

     

    public Form1()
    {
        this.Size = new System.Drawing.Size(600, 800);
        var tv = new TreeView { Parent = this, Dock = DockStyle.Fill };
        var xe = XElement.Load("..\\..\\data.xml");
        Fill(tv.Nodes, xe.XPathSelectElement("//Department[Parent_Dept_Code='00000000']"));
        tv.ExpandAll();
        var nodes = Flatten(tv.Nodes);
        var selected = new List<TreeNode>();
        new TextBox { Parent = this, Dock = DockStyle.Top }
            .TextChanged += (s, e) =>
            {
                var tb = s as TextBox;
                foreach (var n in selected) n.BackColor = Color.Transparent;
                selected.Clear();
                if (string.IsNullOrWhiteSpace(tb.Text))
                    return;
                foreach (var n in nodes.Where(tn => tn.Text.IndexOf(tb.Text, StringComparison.OrdinalIgnoreCase) > -1))
                {
                    n.BackColor = Color.AntiqueWhite;
                    selected.Add(n);
                }
            };
    }
    IEnumerable<TreeNode> Flatten(TreeNodeCollection tc)
    {
        foreach (TreeNode n in tc)
        {
            yield return n;
            foreach (var c in Flatten(n.Nodes)) yield return c;
        }
    }

      
      
    если надо подсветить/выделить часть TreeNode.Text, то см. здесь
     
     

    • Предложено в качестве ответа Malobukv 28 марта 2012 г. 20:17
    • Изменено Malobukv 28 марта 2012 г. 20:32
    • Помечено в качестве ответа Abolmasov Dmitry 5 апреля 2012 г. 9:53
    28 марта 2012 г. 20:17
  • > создать наследников TreeNode. в них надо хранить дополнительную информацию. при поиске по дереву проверять тип узла и выполнять необходимы действия.

     
    примерно так.
     

    using System;
    using System.Collections.Generic;
    using System.Drawing;
    using System.Linq;
    using System.Windows.Forms;
    
    namespace WindowsFormsApplication1
    {
        public partial class Form1 : Form
        {
            public Form1()
            {
                var tv = new TreeView { Dock = DockStyle.Fill, Parent = this };
                var td = new Department() { Text = "Отдел" };
                var ts = new Staff() { Text = "Должность" };
                var p1 = new Person() { Text = "11 22 33", FamilyName = "11" };
                var p2 = new Person() { Text = "Qq Ww 33", FamilyName = "Qq" };
                td.Nodes.Add(ts);
                ts.Nodes.Add(p1);
                ts.Nodes.Add(p2);
                tv.Nodes.Add(td);
                tv.ExpandAll();
    
                var nodes = Flatten(tv.Nodes);
                var selected = new List<TreeNode>();
                var tb = new TextBox { Dock = DockStyle.Top, Parent = this };
                this.Shown += delegate { tb.Focus(); };
                tb.TextChanged += (s, e) =>
                {
                    // убрать фон у выделенных узлов
                    foreach (var n in selected) n.BackColor = Color.Transparent;
                    selected.Clear();
                    if (string.IsNullOrWhiteSpace(tb.Text))
                        return;
    
                    // найти и выделить узлы типа Person, в которых встречается введенный текст
                    foreach (var n in nodes.OfType<Person>().Where(n => n.Text.IndexOf(tb.Text, StringComparison.OrdinalIgnoreCase) > -1))
                    {
                        n.BackColor = Color.Silver;
                        selected.Add(n);
                    }
    
                    // выделить узел типа Person, у которого свойство FamilyName == tb.Text
                    var sn = selected.OfType<Person>().Where(n => n.FamilyName.Equals(tb.Text, StringComparison.OrdinalIgnoreCase)).FirstOrDefault();
                    if (sn != null)
                    {
                        tv.SelectedNode = sn;
                        tv.Focus();
                    }
                };
            }
    
            class Department : TreeNode { }
            class Staff : TreeNode { }
            class Person : TreeNode { public string FamilyName { get; set; } }
    
            IEnumerable<TreeNode> Flatten(TreeNodeCollection tc)
            {
                foreach (TreeNode n in tc)
                {
                    yield return n;
                    foreach (var c in Flatten(n.Nodes)) yield return c;
                }
            }
        }
    }
         
     
    • Изменено Malobukv 3 апреля 2012 г. 13:44
    • Предложено в качестве ответа Malobukv 4 апреля 2012 г. 17:27
    • Помечено в качестве ответа Abolmasov Dmitry 5 апреля 2012 г. 9:53
    3 апреля 2012 г. 13:43

Все ответы

  • > организовать поиск по табельному и Фио сотрудника, которые будут вводиться в textbox?


    в предыдущем примере: public Form1() {...} -- замените следующим кодом:

     

    public Form1()
    {
        this.Size = new System.Drawing.Size(600, 800);
        var tv = new TreeView { Parent = this, Dock = DockStyle.Fill };
        var xe = XElement.Load("..\\..\\data.xml");
        Fill(tv.Nodes, xe.XPathSelectElement("//Department[Parent_Dept_Code='00000000']"));
        tv.ExpandAll();
        var nodes = Flatten(tv.Nodes);
        var selected = new List<TreeNode>();
        new TextBox { Parent = this, Dock = DockStyle.Top }
            .TextChanged += (s, e) =>
            {
                var tb = s as TextBox;
                foreach (var n in selected) n.BackColor = Color.Transparent;
                selected.Clear();
                if (string.IsNullOrWhiteSpace(tb.Text))
                    return;
                foreach (var n in nodes.Where(tn => tn.Text.IndexOf(tb.Text, StringComparison.OrdinalIgnoreCase) > -1))
                {
                    n.BackColor = Color.AntiqueWhite;
                    selected.Add(n);
                }
            };
    }
    IEnumerable<TreeNode> Flatten(TreeNodeCollection tc)
    {
        foreach (TreeNode n in tc)
        {
            yield return n;
            foreach (var c in Flatten(n.Nodes)) yield return c;
        }
    }

      
      
    если надо подсветить/выделить часть TreeNode.Text, то см. здесь
     
     

    • Предложено в качестве ответа Malobukv 28 марта 2012 г. 20:17
    • Изменено Malobukv 28 марта 2012 г. 20:32
    • Помечено в качестве ответа Abolmasov Dmitry 5 апреля 2012 г. 9:53
    28 марта 2012 г. 20:17
  • > После того как  нашёл необходимого сотрудника по событию afterselect должна появляться новая форма, привязанная именно для этого сотрудника. 


    в конструктор Form1 надо добавить примерно следующий код:
     

    tv.AfterSelect += (s, e) => 
    {
       var frm = new SomeForm(e.Node);
       frm.ShowDialog();
    };

     
    или примерно такой код:
     

    var p = new Panel { Parent = this, Dock = DockStyle.Bottom, Height = 200 };
    tv.AfterSelect += (s, e) => 
    {
        p.Controls.Clear();
        new Label { Parent = p, Text = e.Node.Text };   // далее поля ввода
    };  
    
      
      
    28 марта 2012 г. 20:29
  • СПС. Но вот что-то не определяет var nodes = Flatten(tv.Nodes); - что за flatten???

    И вот тут ещё? как мне добавить данный код в buttonclick?? Возникает ошибка в связи с использованием объекта e

    tv.AfterSelect += (s, e) => 
    {
       var frm = new SomeForm(e.Node); 
       frm.ShowDialog();
    };

    И, пожалуйста, можно хоть немного коментировать код...

    30 марта 2012 г. 19:57
  • > не определяет var nodes = Flatten(tv.Nodes); - что за flatten???


    выше по теме есть определение метода Flatten.

    IEnumerable<TreeNode> Flatten(TreeNodeCollection tc)
    {
        foreach (TreeNode n in tc)
        {
            yield return n;
            foreach (var c in Flatten(n.Nodes)) yield return c;
        }
    } 

      
      
       

    31 марта 2012 г. 6:43
  • Да уж, извините, не заметил.
    А как сделать помимо выделения дерево раскрылось  и указатель был на в ведённом сотруднике???

    И как организовать поиск по табельному???

    31 марта 2012 г. 17:57
  • > А как сделать помимо выделения дерево раскрылось  и указатель был на в ведённом сотруднике?
     
     
    в обработчик TextChanged (см. выше в примере) надо добавить примерно такой код:
    var sn = nodes.Where(tn => tn.Text.IndexOf(tb.Text, StringComparison.OrdinalIgnoreCase) > -1).FirstOrDefault();
    if(sn != null)
       sn.TreeView.SelectedNode = sn;

    2 апреля 2012 г. 8:28
  • > как организовать поиск по табельному?


    уточните вопрос. что надо найти?
    в дерево выводятся департаменты, должности, сотрудники. сейчас поиск осуществляется по всем узлам дерева. 
     
     
    2 апреля 2012 г. 8:33
  • Данный поиск находит буквы введённые в textbox, и ищет соответствие данных букв node.text,а нужен поиск только по фамилии. 

    Нужно организовать поиск по табельному сотрудника и фамилии, т.е в xml есть поле Personal_Number и LastName. Вот именно по этим полям при вводе в textbox и должен происходить поиск, а выделять в обоих случаях должно фамилию, т.е. lastName. 

    Нашли первого сотрудника и выделили, затем ищем 2-го и его тоже выделили, а как снять выделение с 1-го и со всех предыдущих??? Т.е. нужно чтобы каждый раз при поиске выделяло только то что мы ищем и ничего больше?


    • Изменено vantur 2 апреля 2012 г. 9:34
    2 апреля 2012 г. 9:11
  • > нужен поиск только по фамилии.
     
     
    т.е. в узлах надо хранить информацию о типе данных. для этого добавляйте в дерево наследников TreeNode. например,

    class Person : TreeNode { public string FamilyName { get; set; } }
    при поиске узлов проверяйте тип узла и есть ли совпадение. примерно так:
    Person p = node as Person;
    if(p != null && p.FamilyName.IndexOf(txt) > -1)
    {
       p.TreeView.SelectedNode = p;
    }
     
     
    2 апреля 2012 г. 12:43
  • что-то не работает, всё равно тоже самое получается...
    А как насчёт других вопросов???
    2 апреля 2012 г. 22:11
  • > что-то не работает, всё равно тоже самое получается...
     
     
    покажите код
     
     
    > организовать поиск по табельному сотрудника и фамилии, т.е в xml есть поле Personal_Number и LastName
     
     
    как уже говорил, надо создать наследников TreeNode. в них надо хранить дополнительную информацию. при поиске по дереву проверять тип узла и выполнять необходимы действия.
     
     
    > Нашли первого сотрудника и выделили, затем ищем 2-го и его тоже выделили, а как снять выделение с 1-го и со всех предыдущих???

      
    выше в примере см. var selected = new List<TreeNode>();
    предназначен для снятия выделение при каждом новом поиске.
     
     
    3 апреля 2012 г. 8:00
  • private void button1_Click(object sender, EventArgs e)
            {
                var nodes = Flatten(treeView3.Nodes);
                var selected = new List<TreeNode>();
                        foreach (var n in selected) n.BackColor = Color.Transparent;
                        selected.Clear();
                        if (string.IsNullOrWhiteSpace(textBox1.Text))
                            return;
                        var sn = nodes.Where(tn => tn.Text.IndexOf(textBox1.Text, StringComparison.OrdinalIgnoreCase) > -1).FirstOrDefault();
                        if (sn != null)
                            sn.TreeView.SelectedNode = sn;
                        foreach (var n in nodes.Where(tn => tn.Text.IndexOf(textBox1.Text, StringComparison.OrdinalIgnoreCase) > -1))
                        {
                            n.BackColor = Color.LightBlue;
                            selected.Add(n);
                        }                   
                       
            }
    
            IEnumerable<TreeNode> Flatten(TreeNodeCollection tc)
            {
                foreach (TreeNode n in tc)
                {
                    yield return n;
                    foreach (var c in Flatten(n.Nodes)) yield return c;
                }
            }

     var selected = new List<TreeNode>(); - предназначен, но почему не очищает??? Где повторно нужно его вызвать в коде?

    Вы говорили: надо создать наследников TreeNode. в них надо хранить дополнительную информацию. при поиске по дереву проверять тип узла и выполнять необходимы действия.

    Реализуйте, пожалуйста, данное в приведенном коде, а то что-то я вообще не пойму как это сделать...

    3 апреля 2012 г. 9:16
  • > var selected = new List<TreeNode>(); - предназначен, но почему не очищает?
     
      
    selected должен быть определен за пределами обработчика button1_Click, примерно так:
    List<TreeNode> selected = new List<TreeNode>();
    private void button1_Click(object sender, EventArgs e)
    {
    }
     
    3 апреля 2012 г. 10:36
  • > создать наследников TreeNode. в них надо хранить дополнительную информацию. при поиске по дереву проверять тип узла и выполнять необходимы действия.

     
    примерно так.
     

    using System;
    using System.Collections.Generic;
    using System.Drawing;
    using System.Linq;
    using System.Windows.Forms;
    
    namespace WindowsFormsApplication1
    {
        public partial class Form1 : Form
        {
            public Form1()
            {
                var tv = new TreeView { Dock = DockStyle.Fill, Parent = this };
                var td = new Department() { Text = "Отдел" };
                var ts = new Staff() { Text = "Должность" };
                var p1 = new Person() { Text = "11 22 33", FamilyName = "11" };
                var p2 = new Person() { Text = "Qq Ww 33", FamilyName = "Qq" };
                td.Nodes.Add(ts);
                ts.Nodes.Add(p1);
                ts.Nodes.Add(p2);
                tv.Nodes.Add(td);
                tv.ExpandAll();
    
                var nodes = Flatten(tv.Nodes);
                var selected = new List<TreeNode>();
                var tb = new TextBox { Dock = DockStyle.Top, Parent = this };
                this.Shown += delegate { tb.Focus(); };
                tb.TextChanged += (s, e) =>
                {
                    // убрать фон у выделенных узлов
                    foreach (var n in selected) n.BackColor = Color.Transparent;
                    selected.Clear();
                    if (string.IsNullOrWhiteSpace(tb.Text))
                        return;
    
                    // найти и выделить узлы типа Person, в которых встречается введенный текст
                    foreach (var n in nodes.OfType<Person>().Where(n => n.Text.IndexOf(tb.Text, StringComparison.OrdinalIgnoreCase) > -1))
                    {
                        n.BackColor = Color.Silver;
                        selected.Add(n);
                    }
    
                    // выделить узел типа Person, у которого свойство FamilyName == tb.Text
                    var sn = selected.OfType<Person>().Where(n => n.FamilyName.Equals(tb.Text, StringComparison.OrdinalIgnoreCase)).FirstOrDefault();
                    if (sn != null)
                    {
                        tv.SelectedNode = sn;
                        tv.Focus();
                    }
                };
            }
    
            class Department : TreeNode { }
            class Staff : TreeNode { }
            class Person : TreeNode { public string FamilyName { get; set; } }
    
            IEnumerable<TreeNode> Flatten(TreeNodeCollection tc)
            {
                foreach (TreeNode n in tc)
                {
                    yield return n;
                    foreach (var c in Flatten(n.Nodes)) yield return c;
                }
            }
        }
    }
         
     
    • Изменено Malobukv 3 апреля 2012 г. 13:44
    • Предложено в качестве ответа Malobukv 4 апреля 2012 г. 17:27
    • Помечено в качестве ответа Abolmasov Dmitry 5 апреля 2012 г. 9:53
    3 апреля 2012 г. 13:43
  • А как мне задать FamilyName именно для всех сотрудников, прописывать вручную для всех?

    Что-то не совсем понятно... Можно данный код изменить именно для моего treeview и моего xml и привести текст? СПС...

    3 апреля 2012 г. 17:03
  • > А как мне задать FamilyName именно для всех сотрудников, прописывать вручную для всех?
     
     
    дерево заполняется в методе Fill (см. выше);
    в нем есть строка
    tn.Nodes.Add(p.LastName + " " + p.FirstName);
    ее надо заменить на следующую:
    tn.Nodes.Add(new Person { Text = p.LastName + " " + p.FirstName, FamilyName = p.LastName });
     
     
    • Изменено Malobukv 3 апреля 2012 г. 20:25
    • Помечено в качестве ответа vantur 5 апреля 2012 г. 7:45
    3 апреля 2012 г. 20:24