Note: Forums will be making significant UX changes to address key usability improvements surrounding search, discoverability and navigation. To learn more about these changes please visit the announcement which can be found HERE.
c#: Создание и заполнение treeview из нескольких таблиц Mysql

Answered c#: Создание и заполнение treeview из нескольких таблиц Mysql

  • 16 марта 2012 г. 15:46
     
      С кодом

    Здравствуйте. И сразу к делу...

    Есть 4 таблицы mysql:

    CREATE TABLE `HR`.`Department` (
      `Dept_code` int(11) NOT NULL,
      `Parent_Dept_code` int(11) NOT NULL,
      `Full_name_d` varchar(250) NOT NULL,
      `Short_name_d` varchar(80),
       PRIMARY KEY (`Dept_code`)); 
    
    CREATE TABLE `HR`.`post` (
      `Post_code` int(11) NOT NULL,
      `Full_name_p` varchar(250) NOT NULL,
      `Short_name_p` varchar(80),
      `Chief_code` int,
       PRIMARY KEY (`Post_code`)); 
    
    CREATE  TABLE `HR`.`Staff` (
      `Personal_n` INT(11) NOT NULL,
      `LName` VARCHAR(60) NOT NULL,
      `FName` VARCHAR(30) NOT NULL,
      `Mname` VARCHAR(40) NOT NULL,
       PRIMARY KEY (`Personal_n`)); 
    
    CREATE TABLE `HR`.`Relation` (
      `idrelation` int(11) NOT NULL,
      `staff_rel` INT(11) NOT NULL,
      `Dept_code_rel` int(11) NOT NULL,
      `Post_code_rel` int(11) NOT NULL,
      PRIMARY KEY (`idrelation`),
    FOREIGN KEY (`staff_rel`) REFERENCES staff (`Personal_n`),
    FOREIGN KEY (`Dept_code_rel`) REFERENCES Department (`Dept_code`),
    FOREIGN KEY (`Post_code_rel`) REFERENCES Post (`Post_code`)); 

    Нужно чтобы при запуске программы (VS2010, c#) создавался treeview на основании всех этих таблиц...
    Должно быть что-то вроде:

    (2 отдела (в отделе post - staff) в них по несколько бюро, в каждом бюро несколько post и за каждым  Personal_n закреплён свой  Post_code (названия post повторяются):

    -department (отдел)
            - post
                 -staff
       -department(бюро)
            - post
                 -staff
             - post
                  -staff
                  -staff
    и т.д. всё заново...

    Вот каким образом я вывел отделы:

    public MySqlConnection myConnection; string Connect = "Database=HR;Data Source=localhost;User Id=root;Password=root"; MySqlDataAdapter Adapt; private void Form1_Load(object sender, EventArgs e) { try { myConnection = new MySqlConnection(Connect); myConnection.Open(); DataTable dtTree = new DataTable(); string sql = "select Dept_code, Parent_Dept_code, Short_name_d from `hr`.`department`"; Adapt = new MySqlDataAdapter(sql, myConnection); Adapt.Fill(dtTree); Adapt.Dispose(); treeView1.BeginUpdate(); treeView1.Nodes.Clear();

    CreateTreeView(treeView1.Nodes, 0, dtTree); treeView1.Nodes[0].Expand(); treeView1.Select(); treeView1.EndUpdate(); myConnection.Close(); } catch (Exception ex) { MessageBox.Show(ex.ToString()); } } protected void CreateTreeView(TreeNodeCollection parentNode, int parentID, DataTable mytab) { foreach (DataRow dta in mytab.Rows) { if (Convert.ToInt32(dta["Parent_Dept_code"]) == parentID) { String key = dta["Dept_code"].ToString(); String text = dta["Short_name_d"].ToString(); TreeNodeCollection newParentNode = parentNode.Add(key, text).Nodes; CreateTreeView(newParentNode, Convert.ToInt32(dta["Dept_code"]), mytab); } } }

    Здесь есть поле parent_dept_code, что существенно упрощает задачу. А таблицы staff, post и department  связанны только через таблицу relation.

    Помогите, а то уже неделю голову ломаю... желательно с конкретными примерами.








    • Изменено vantur 16 марта 2012 г. 15:52
    •  

Все ответы

  • 16 марта 2012 г. 19:52
    Модератор
     
     
    "Помогите, а то уже неделю голову ломаю... желательно с конкретными примерами." - А в чём собственно проблема? Нужно её понять, чтобы попытаться решить.
  • 17 марта 2012 г. 6:12
     
      С кодом

    Нужно чтобы при запуске программы (VS2010, c#) создавался treeview на основании всех этих таблиц...
    это по ламерски, а мне нужно что бы при запуске программы treeview создавался и заполнялся полностью без помощи пользователя. На сколько я понял нужно использовать рекурсию. И тут проблемка, что одной должности со своим id соответствует свой  id сотрудника, но названия должностей совпадают... 

    //добавление должности по селекту бюро
    
    private void treeView1_AfterSelect(object sender, TreeViewEventArgs e)
            {
                myConnection = new MySqlConnection(Connect);
                myConnection.Open();
                DataTable dtTree = new DataTable();
                string sql = "select Short_name_p from  `hr`.`department`, `hr`.`post`, `hr`.`relation`,  `hr`.`staff` where (post_code=post_code_rel) and (dept_code=dept_code_rel) and (Personal_n=Staff_rel) and (Short_name_d='" + treeView1.SelectedNode.Text + "')";
                Adapt = new MySqlDataAdapter(sql, myConnection);
                Adapt.Fill(dtTree);
                Adapt.Dispose();
                foreach (DataRow dta in dtTree.Rows)
                {
                    TreeNode childNode = new TreeNode(dta["Short_name_p"].ToString());
    
                    treeView1.SelectedNode.Nodes.Add(childNode);
                }
                myConnection.Close();
            }
    
    // добавление сотрудника по NodeMouseDoubleClick должности
            private void 
    treeView1_NodeMouseDoubleClick(object sender, TreeNodeMouseClickEventArgs e)
            {
                myConnection = new MySqlConnection(Connect);
                myConnection.Open();
                DataTable dtTree = new DataTable();
                string sql = "select Lname,FName,MName from  `hr`.`department`,`hr`.`post`, `hr`.`relation`, `hr`.`staff` where (post_code=post_code_rel) and (dept_code=dept_code_rel) and (Personal_n=Staff_rel) and (Short_name_p='" + treeView1.SelectedNode.Text + "')";
    
                Adapt = new MySqlDataAdapter(sql, myConnection);
                Adapt.Fill(dtTree);
                Adapt.Dispose();
                foreach (DataRow dta in dtTree.Rows)
                {
                    TreeNode childNode = new TreeNode(dta["Lname"].ToString() + " " + dta["FName"].ToString() + " " + dta["MName"].ToString());
                    treeView1.SelectedNode.Nodes.Add(childNode);
                }
                myConnection.Close();
            }
    Должно быть: 

  • 17 марта 2012 г. 7:49
    Модератор
     
      С кодом

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

    /*Таблица отделов, один отдел может содержать другие т.е. отношение предок - потомок? Если так то тут нужны возвратные(рекурсивные)
    отнощения. В вашем случае Parent_Dept_code должен быть внешним по отношению к Dept_code. 
    Т.е. FOREIGN KEY (`Parent_Dept_code`) REFERENCES Department (`Dept_code`).
    */
    CREATE TABLE `HR`.`Department` (
      `Dept_code` int(11) NOT NULL,
      `Parent_Dept_code` int(11) NOT NULL,
      `Full_name_d` varchar(250) NOT NULL,
      `Short_name_d` varchar(80),
       PRIMARY KEY (`Dept_code`)); 
    
    CREATE TABLE `HR`.`post` (
      `Post_code` int(11) NOT NULL,
      `Full_name_p` varchar(250) NOT NULL,
      `Short_name_p` varchar(80),
      `Chief_code` int, /*Что за код?*/
       PRIMARY KEY (`Post_code`)); 
    /*
    Один сотрудник может иметь несколько должностей, или нет?
    */
    CREATE  TABLE `HR`.`Staff` (
      `Personal_n` INT(11) NOT NULL,
      `LName` VARCHAR(60) NOT NULL,
      `FName` VARCHAR(30) NOT NULL,
      `Mname` VARCHAR(40) NOT NULL,
       PRIMARY KEY (`Personal_n`)); 
    
    CREATE TABLE `HR`.`Relation` (
      `idrelation` int(11) NOT NULL,
      `staff_rel` INT(11) NOT NULL,/*Если столбец не нулевой, значит если есть должность и сотрудник должен быть, а если место свободное, или такого не бывает? */
      `Dept_code_rel` int(11) NOT NULL,
      `Post_code_rel` int(11) NOT NULL,
      PRIMARY KEY (`idrelation`),
    FOREIGN KEY (`staff_rel`) REFERENCES staff (`Personal_n`),
    FOREIGN KEY (`Dept_code_rel`) REFERENCES Department (`Dept_code`),
    FOREIGN KEY (`Post_code_rel`) REFERENCES Post (`Post_code`)); 

  • 17 марта 2012 г. 10:10
     
     
    дело в том что данные таблицы я загоняю в mysql из xml-файла, который мне нельзя менять... 
    Chief_code - это код, который описывает принадлежность данной должности к главной должности отдела, в моём случае начальник управления. т.е. все должности подчиняются должности начальника управления...
  • 17 марта 2012 г. 17:10
     
     Отвечено С кодом

    > Нужно чтобы при запуске программы (VS2010, c#) создавался treeview на основании всех этих таблиц... [...] -department (отдел) - post - staff ...


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

    using System.Data;
    using System.IO;
    using System.Windows.Forms;
    
    namespace WindowsFormsApplication1
    {
        public partial class Form1 : Form
        {
            public Form1()
            {
                var ds = new DataSet("org");
                ds.ReadXml(new StringReader(@" <!-- test -->
                    <departament name='d1'>
                        <post name='p1'>
                            <staff name='fio1' />
                        </post>
                        <departament name='d2'>
                            <post name='p2'>
                                <staff name='fio2' />
                                <staff name='fio3' />
                            </post>
                        </departament>
                        <departament name='d3'>
                            <post name='p3' />
                        </departament>
                        <departament name='d4' />
                    </departament>"));
    
                foreach (DataTable dt in ds.Tables)
                    foreach (DataColumn dc in dt.Columns)
                        if (dc.ColumnMapping == MappingType.Hidden)
                            dc.ColumnMapping = MappingType.Element;
    
                this.Size = new System.Drawing.Size(900, 700);
                var sc = new SplitContainer { Parent = this, Dock = DockStyle.Fill, SplitterDistance = (int)(this.Width * .45) };
                var dg = new DataGrid { DataSource = ds, Dock = DockStyle.Fill, Parent = sc.Panel2, ReadOnly = true };
                new RichTextBox { Parent = sc.Panel2, Dock = DockStyle.Bottom, Height = 350, Text = ds.GetXml() };
    
                var tv = new TreeView { Dock = DockStyle.Fill, Parent = sc.Panel1 };
                foreach (DataRow dr in ds.Tables["departament"].Rows)
                    if (dr.GetParentRow("departament_departament") == null)
                        Fill(tv.Nodes, dr);
    
                tv.ExpandAll();
    
                this.Shown += (s, e) =>
                {
                    dg.Focus();
                    SendKeys.SendWait("%({DOWN})");
                    tv.Focus();
                };
            }
    
            private static void Fill(TreeNodeCollection nodes, DataRow dr)
            {
                var dn = nodes.Add((string)dr["name"]);
    
                var ps = dr.GetChildRows("departament_post");
                if (ps != null)
                    foreach (DataRow pr in ps)
                    {
                        var pn = dn.Nodes.Add((string)pr["name"]);
                        var ss = pr.GetChildRows("post_staff");
                        if (ss != null)
                            foreach (DataRow sr in ss)
                                pn.Nodes.Add((string)sr["name"]);
                    }
    
                var ds = dr.GetChildRows("departament_departament");
                if (ds != null)
                    foreach (DataRow cr in ds)
                        Fill(dn.Nodes, cr);
            }
        }
    }
       

       

  • 18 марта 2012 г. 6:50
     
     
    Но данный пример составляет treview из xml и в таком же виде выводит, а мне нужно выводить информацию между тегами, а не их самих (смотрите рисунок выше). Можно немного пояснить код или создать пример именно для решения моей задачи? спс...
    • Изменено vantur 18 марта 2012 г. 7:02
    •  
  • 18 марта 2012 г. 7:53
     
     
    > данный пример составляет treview из xml и в таком же виде выводит
     
      
    пример выводит данные из DataSet. как они попадают в DataSet не имеет значения. 
    данные могут быть загружены из xml (как в примере) или из базы данных.
     
     
  • 19 марта 2012 г. 7:07
     
     Предложенный ответ

    Т.е. вам нужно загрузить вашу базу полностью в DataSet с сохранением отношений между таблицами (можно в проект в Solution Explorer добавить новый элемент DataSet, после открыть его в дизайнере и перетащить из Server Explorer необходимы таблицы, после чего проверить связи между ними; далее в коде заполнить DataSet с помощью сгененрированных TableAdapter-ов) . А после уже воспользоваться возможностями получения родительский/дочерних строк для заполнения treeview.

    Если ответ Malobukv решает вашу проблему, то пожалуйста, не забудьте отметить его как ответ (кнопка под сообщением).

    Спасибо.


    Для связи [mail]

  • 22 марта 2012 г. 22:50
     
      С кодом

    Вот что у меня получилось с использованием DataSet:

        private void button5_Click(object sender, EventArgs e)
            {
                this.postTableAdapter1.Fill(this.hrDataSet.post);
                this.departmentTableAdapter1.Fill(this.hrDataSet.department);
                this.relationTableAdapter1.Fill(this.hrDataSet.relation);
                this.staffTableAdapter1.Fill(this.hrDataSet.staff);
    
                foreach (DataRow dr in this.hrDataSet.relation.Rows)  // сначала пробежал по всем строкам главной таблицы
                {
                    TreeNode node = new TreeNode();
                    string n = dr["dept_code_rel"].ToString();
    
                    // пробегаюсь по строкам подчиненной таблицы, но только по тем, которые относятся к текущей строке главной таблицы
                    foreach (DataRow r in this.hrDataSet.department.Select("dept_code = " + n))
                    {
                        node.Text = r["Short_name_d"].ToString();
                        treeView2.Nodes.Add(node);
    
                            TreeNode node1 = new TreeNode();
                            node1.Name = dr["post_code_rel"].ToString();
    
                            foreach (DataRow r1 in this.hrDataSet.post.Select("post_code = " + node1.Name))
                            {
                                node1.Text = r1["Short_name_p"].ToString();
                                node.Nodes.Add(node1);
    
                                TreeNode node2 = new TreeNode();
                                node2.Name = dr["staff_rel"].ToString();
    
                                foreach (DataRow q in this.hrDataSet.staff.Select("personal_n = " + node2.Name))
                                {
                                    node2.Text = q["LName"].ToString() + " " + q["FName"].ToString() + " " + q["MName"].ToString();
                                    node1.Nodes.Add(node2);
                                }
                            }
    
                        }
                    }
                }

    Слева изображена приблезительная структура, которая должна быть.              Справа - то что получилось по приведённому коду

    Т.е, что должно быть:

    • -управление
    •      -начальник управления
    •            - ФИО
    •       - экономист
    •             - ФИО
    •  - отдел АСУП
    •        - начальник отдела
    •              - фио
    •        - бюро *
    •               - Должность (может повторяться)
    •                   - фио
    • - отдел САПР
    •         - начальник отдела
    •                - фио
    •        - бюро *
    •                  -должность
    •                        - фио 

    Для построения такой структуры нужно как-то изменить приведённый код с использованием рекурсии, но я в ней вообще ничего не понимаю. 
    Исправте, пожалуйста, код с использование рекурсии или хотя бы приведите примеры для моего случая. СПС...


    • Изменено vantur 22 марта 2012 г. 22:52
    •  
  • 23 марта 2012 г. 5:09
     
     
    > Для построения такой структуры нужно как-то изменить приведённый код ...
     
      
    можно ли изменить структуру базы? что возвращает метод this.hrDataSet.GetXml()?
     
     
  • 23 марта 2012 г. 10:11
     
     
    Структуру желательно не менять, так как все данные и сами таблицы беру из xml. А где вы увидели в предыдущем коде метод this.hrDataSet.GetXml()???
  • 23 марта 2012 г. 13:33
     
     
    > А где вы увидели в предыдущем коде метод this.hrDataSet.GetXml()?
       

    покажите xml, который возвращает метод GetXml. возможно, что проще заполнить TreeView на основе xml, а не на основе DataSet.
      
     
  • 23 марта 2012 г. 14:02
     
      С кодом
    <?xml version=""1.0""?><ns0:Enterprise Date=""13.02.1000"" xmlns:ns0=""http://SAPToAISApplication.SAPData"">
    <Classifiers>
    <Classifier_Titles>
    <Title>
    	<Title_Code>70011946</Title_Code>
    	<Full_Name>НАЧАЛЬНИК УПРАВЛЕНИЯ</Full_Name>
    	<Short_Name>НАЧАЛЬНИК УПРАВЛЕНИЯ</Short_Name>
    	<Date_From>01.01.1900</Date_From>
    	<Date_To>31.12.9999</Date_To>
    </Title>
    </Classifier_Titles>
    
    <Classifier_Staff>
    <Staff>
    	<Personal_Number>00034893</Personal_Number>
    	<LName>Фамилия</LName>
    	<FName>Имя</FName>
    	<MName>Отчество</MName>
    	<Date_From>09.01.2012</Date_From>
    	<Date_To>31.12.9999</Date_To>
    </Staff>
    </Classifier_Staff>
    
    <Classifier_Department>
    <Department>
    	<Dept_Code>51001583</Dept_Code>
    	<Parent_Dept_Code>00000000</Parent_Dept_Code>
    	<Full_Name>УПРАВЛЕНИЕ</Full_Name>
    	<Short_Name>УПРАВЛЕНИЕ</Short_Name>
    	<Date_From>00.00.0000</Date_From>
    	<Date_To>00.00.0000</Date_To>
    </Department>
    </Classifier_Department>
    
    </Classifiers>
    
    <Relation_Staff_Department_Titles_Vice>
    <Relation>
    	<Personal_Number>00034844</Personal_Number>
    	<Dept_Code>51001586</Dept_Code>
    	<Titles_Codes>
    		<Title_Code>70011946</Title_Code>
    	</Titles_Codes>
    </Relation>
    </Relation_Staff_Department_Titles_Vice>
    </ns0:Enterprise>";
    Вот пример по 1 сотруднику. Всего 90... Что должно быть смотрите выше...
  • 25 марта 2012 г. 19:34
     
      С кодом
    > Вот пример по 1 сотруднику.
     
     
    примерно так: 
      
    using System.Windows.Forms;
    using System.Xml.Linq;
    using System.Xml.XPath;
    
    namespace WindowsFormsApplication1
    {
        public partial class Form1 : Form
        {
            public Form1()
            {
                var tv = new TreeView { Parent = this, Dock = DockStyle.Fill };
                var xe = XElement.Load("data.xml");
                foreach (var d in xe.XPathSelectElements("//Department[Parent_Dept_Code='00000000']"))
                    Run(d, tv.Nodes);
                tv.ExpandAll();
            }
    
            void Run(XElement d, TreeNodeCollection nc)
            {
                var dc = d.Element("Dept_Code").Value;
                var nn = nc.Add(d.Element("Full_Name").Value);
                
                var re = d.XPathSelectElement("//Relation[Dept_Code/text()='" + dc + "']");
                var pn = re.Element("Personal_Number");
                foreach(var t in re.Element("Titles_Codes").Elements("Title_Code"))
                {
                    foreach(var x in d.XPathSelectElements("//Title[Title_Code='" + t.Value + "']"))
                    {
                        var s = nn.Nodes.Add(x.Element("Full_Name").Value);
                        var p = x.XPathSelectElement("//Staff[Personal_Number='" + pn.Value + "']");
                        if(p != null)
                            s.Nodes.Add(p.Element("LName").Value);
                    }
                }
                foreach (var s in d.XPathSelectElements("//Department[Parent_Dept_Code='" + dc + "']"))
                    Run(s, nn.Nodes);
            }
        }
    }
        
       
  • 25 марта 2012 г. 22:54
     
      С кодом

    Извините, но изменились поля в xml. При разборе вашего кода и замене на нужные имена полей почти в каждой строчке выдаёт ошибку: Object reference not set to an instance of an object.

    Вот новый xml... Что нужно изменить в вашем коде? СПС...

    <?xml version="1.0" encoding="utf-8"?>
    <ns0:Enterprise Date="13.02.2012" xmlns:ns0="http://SAPToAISApplication.SAPData">
    <Classifiers>
        <Classifier_Titles>
          <Title>
            <Title_Code>70011946</Title_Code>
            <Full_Name>НАЧАЛЬНИК УПРАВЛЕНИЯ</Full_Name>
            <Short_Name>НАЧАЛЬНИК УПРАВЛЕНИЯ</Short_Name>
            <Date_From>01.01.1900</Date_From>
            <Date_To>31.12.9999</Date_To>
          </Title>
         </Classifier_Titles>   
    
        <Classifier_Staff>
          <Staff>
            <Personal_Number>00034893</Personal_Number>
            <LName>Фамилия</LName>
            <FName>Имя</FName>
            <MName>Отчество</MName>
            <Date_From>09.01.2012</Date_From>
            <Date_To>31.12.9999</Date_To>
          </Staff>
        </Classifier_Staff>
    
        <Classifier_Department>
          <Department>
            <Dept_Code>51001583</Dept_Code>
            <Parent_Dept_Code>00000000</Parent_Dept_Code>
            <Full_Name1>УПРАВЛЕНИЕ ИНФОРМАЦИОННЫХ СИСТЕМ</Full_Name1>
            <Short_Name1>УИС</Short_Name1>
            <Date_From>00.00.0000</Date_From>
            <Date_To>00.00.0000</Date_To>
          </Department>
        </Classifier_Department>
    </Classifiers>
    
       <Relation_Staff_Department_Titles_Vice>
        <Relation>
          <Personal_Number1>00034893</Personal_Number1>
          <Dept_Code1>51001586</Dept_Code1>
          <Titles_Codes>
            <Title_Code2>70011946</Title_Code2>
          </Titles_Codes>
        </Relation>
       </Relation_Staff_Department_Titles_Vice>
    </ns0:Enterprise>
    

  • 26 марта 2012 г. 5:31
     
      С кодом

    > изменились поля в xml. [...] Вот новый xml... Что нужно изменить в вашем коде?

           

    using System.Windows.Forms;
    using System.Xml.Linq;
    using System.Xml.XPath;
    
    namespace WindowsFormsApplication1
    {
        public partial class Form1 : Form
        {
            public Form1()
            {
                var tv = new TreeView { Parent = this, Dock = DockStyle.Fill };
                var xe = XElement.Load("data.xml");
                foreach (var d in xe.XPathSelectElements("//Department[Parent_Dept_Code='00000000']"))
                    Run(d, tv.Nodes);
                tv.ExpandAll();
            }
    
            void Run(XElement d, TreeNodeCollection nc)
            {
                var dc = d.Element("Dept_Code").Value;
                var nn = nc.Add(d.Element("Full_Name1").Value);
                
                var re = d.XPathSelectElement("//Relation[Dept_Code1/text()='" + dc + "']");
                var pn = re.Element("Personal_Number1");
                foreach(var t in re.Element("Titles_Codes").Elements("Title_Code2"))
                {
                    foreach(var x in d.XPathSelectElements("//Title[Title_Code='" + t.Value + "']"))
                    {
                        var s = nn.Nodes.Add(x.Element("Full_Name").Value);
                        var p = x.XPathSelectElement("//Staff[Personal_Number='" + pn.Value + "']");
                        if(p != null)
                            s.Nodes.Add(p.Element("LName").Value);
                    }
                }
                foreach (var s in d.XPathSelectElements("//Department[Parent_Dept_Code='" + dc + "']"))
                    Run(s, nn.Nodes);
            }
        }
    }
       
       
    код работает, если в xml: "<Dept_Code1>51001586</Dept_Code1>" заменить на "<Dept_Code1>51001583</Dept_Code1>" - иначе нет связи между департаментом и должностью.
      
       
  • 26 марта 2012 г. 16:52
     
     

    Всё равно ошибка в строке  var pn = re.Element("Personal_Number1");

    Не могу понять в чём дело... Вот весь xml. Посмотрите чё не так... СПС...

    xml


  • 26 марта 2012 г. 17:28
     
     Предложенный ответ С кодом

    > ошибка в строке varpn =re.Element("Personal_Number1");
     
     
    т.к. бывает, чтор re == null -- в ситуации, когда у подразделения нет должностей.
    решение:

    using System.Windows.Forms;
    using System.Xml.Linq;
    using System.Xml.XPath;
    
    namespace WindowsFormsApplication1
    {
        public partial class Form1 : Form
        {
            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");
                foreach (var d in xe.XPathSelectElements("//Department[Parent_Dept_Code='00000000']"))
                    Run(d, tv.Nodes);
                tv.ExpandAll();
            }
            void Run(XElement d, TreeNodeCollection nc)
            {
                var dc = d.Element("Dept_Code").Value;
                var nn = nc.Add(d.Element("Full_Name1").Value);
                var re = d.XPathSelectElement("//Relation[Dept_Code1/text()='" + dc + "']");
                if (re != null)
                {
                    var pn = re.Element("Personal_Number1");
                    foreach (var t in re.Element("Titles_Codes").Elements("Title_Code2"))
                    {
                        foreach (var x in d.XPathSelectElements("//Title[Title_Code='" + t.Value + "']"))
                        {
                            var s = nn.Nodes.Add(x.Element("Full_Name").Value);
                            var p = x.XPathSelectElement("//Staff[Personal_Number='" + pn.Value + "']");
                            if (p != null)
                                s.Nodes.Add(p.Element("LName").Value);
                        }
                    }
                }
                foreach (var s in d.XPathSelectElements("//Department[Parent_Dept_Code='" + dc + "']"))
                    Run(s, nn.Nodes);
            }
        }
    }

    • Предложено в качестве ответа Malobukv 27 марта 2012 г. 14:45
    •  
  • 26 марта 2012 г. 22:04
     
     

    СПС. Данный код работает. Только вот почему-то не вывело начальника отдела АСУП???

    Но он выводит только отделы и их начальников, а мне нужно  все должности по отделам, примерно как на скрине:

    Нужно выводить начальников отделов и должности этого отдела, которые не должны  повторяются в пределах этого бюро (на скрине они повторяются, что не верно)

    Т.е., к примеру, ветка Инж. программист 1К, Инж. программист 2К  в каком-то бюро должна быть одна и содержать сотрудников этого бюро по этой должности. И так для всех бюро и должностей.


    • Изменено vantur 26 марта 2012 г. 22:07
    •  
  • 27 марта 2012 г. 14:45
     
     Отвечено С кодом

    > Нужно выводить начальников отделов и должности этого отдела, которые не должны  повторяются в пределах этого бюро
      

     

    using System;
    using System.Linq;
    using System.Windows.Forms;
    using System.Xml.Linq;
    using System.Xml.XPath;
    namespace WindowsFormsApplication1
    {
        public partial class Form1 : Form
        {
            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();
            }
            void Fill(TreeNodeCollection nc, XElement xd)
            {
                Func<string, XElement> findTitle = code => xd.XPathSelectElement("//Title[Title_Code='" + code + "']");
                var dc = xd.Element("Dept_Code").Value;
                var nn = nc.Add(xd.Element("Short_Name1").Value);
                var rels =
                    from x in xd.XPathSelectElements("//Relation[Dept_Code1='" + dc + "']")
                    let position = findTitle(x.XPathSelectElement("Titles_Codes/Title_Code2[1]").Value)
                    let chief = findTitle(position.XPathSelectElement("Chief_Title_Codes/Title_Code1[1]").Value)
                    select new
                    {
                        Person = x.XPathSelectElement("//Staff[Personal_Number='" + x.Element("Personal_Number1").Value + "']"),
                        Position = position,
                        Chief = chief
                    };
                var details =
                    from x in rels
                    select new
                    {
                        LastName = x.Person.Element("LName").Value,
                        FirstName = string.Concat(x.Person.Element("FName").Value, " ", x.Person.Element("MName").Value),
                        Title = x.Position.Element("Short_Name").Value,
                    };
                foreach (var x in details.GroupBy(d => d.Title))
                {
                    var tn = nn.Nodes.Add(x.Key);
                    foreach (var p in x.OrderBy(n => n.LastName))
                        tn.Nodes.Add(p.LastName + " " + p.FirstName);
                }
                foreach (var s in xd.XPathSelectElements("//Department[Parent_Dept_Code='" + dc + "']"))
                    Fill(nn.Nodes, s);
            }
        }
    }
        
      
    • Предложено в качестве ответа Malobukv 27 марта 2012 г. 14:49
    • Помечено в качестве ответа vantur 27 марта 2012 г. 21:42
    •