使用多線程載入多個Xml檔案到TreeView控制項

來源:互聯網
上載者:User
treeview|xml|多線程|載入|控制項 在很多情況下程式員需要採用多線程來開發應用程式,使用者可以在前台操作資料或其他工作,在背景程式正在載入很大的一些檔案,而這一過程不會影響到前台的使用者。在這篇文章中,我來講述一下怎樣通過多個線程來載入多個檔案。在這個例子中我們將來研究這樣一件事情,讀取多個Xml檔案並通過TreeView把它們顯示出來。我們可以通過資料庫來完成,不過為了保持例子的簡單這裡採用了Xml檔案。 你會注意到我們有兩個xml檔案同原代碼放在一起。程式使用者介面如下:
 Filedisplayer類用來顯示上面的表單。表單的包括一些按紐:瀏覽按紐,運行按紐,終止按紐以及退出按紐。應用程式可以通過點擊退出按紐來結束整個程式的運行。當點擊瀏覽的時候會開啟一個檔案選擇對話方塊來載入Xml檔案。當然你也可以直接在文字框中輸入檔案全路徑。private void selectbutton_click(object sender, System.EventArgs e){     OpenFileDialog openFileDialog1 = new OpenFileDialog();     openFileDialog1.Filter = "All Files (*.*)|*.*|Text Files (*.txt)|*.txt";     if (openFileDialog1.ShowDialog () == DialogResult.OK)      {         String fileName = openFileDialog1.FileName;         //如果副檔名為xml,選擇成功         if ( (fileName.Length != 0) && (fileName.EndsWith("xml")))         {              filename_box.Text=fileName;         }     }} 一旦選擇了一個檔案,使用者可以通過點擊運行來讀取檔案資料。顯示的結果就如上面TreeView中所看到的。這篇文章的主要目的就是給讀者一個方法來執行多線程。終止按紐用來退出執行的任務。 現在我們已經習慣的各種使用者介面控制項,那就讓我們來研究其他部分。你可以在代碼中注意到我們已經編寫了下面一些代碼(如下):private Thread QueueMonitorThread ;//定義一個線程,用來監視隊列private RequestQueue req_queue;//放了載入的檔案資訊(檔案名稱)private bool m_bAbort;//通過這標誌來控制 QueueMonitorThreadprivate ThreadEventDelegate onTreeViewElement;//非同步代理程式調用,切換線程來更新TreeView在RequestQueue.CS檔案中我們定義了一個RequestQueue類,他是一個隊列用來隱藏檔名資料。在這個例子中設定了隊列的容量為5。因此隊列最多能放五個檔案名稱在裡面。在Add方法中有一個邏輯,如果添加檔案成功返回1,如果失敗(隊列為滿)返回0;Remove方法用來移動隊列頭索引,如果頭索引等與尾索引那隊列就為空白了;getFile方法是用來擷取隊列最前面的項。如果為空白返回0, setSize方法用來重新設定隊列的容量,如果調用原來的資料就會被扔掉(這裡作者是用數組來類比環形隊列,設定容量會重新執行個體化一個數組);isEmpty方法用來判斷隊列是否有空。 備忘:你也可以使用System.Collections命名空間下的Queue類。 當點擊了運行按紐後,程式會從擷取路徑文字框中擷取檔案名稱並把它加入到FileInfo結構(很奇怪這裡作者的結構只是存了一個string)。最後把這個結構加入到了隊列。QueueMonitorThread線程會半秒鐘去掃描一次隊列。private void processbutton_click(object sender, System.EventArgs e){     FileInfo f = new FileInfo();     f.fName=this.filename_box.Text;     //如果隊列已滿那就等待隊列有空時再添加FilInfo     while ( req_queue.isEmpty()!=1)     {         if( req_queue.isEmpty() == 1 )              break;         Thread.Sleep(200);     }     req_queue.add(f);}下面是繼承表單的建構函式。public filedisplayer(){     InitializeComponent();     req_queue = new RequestQueue();     //設定隊列容量為5     req_queue.setSize(5);     //預設監視線程沒有終止     m_bAbort = false;     //執行個體會監視線程     QueueMonitorThread = new Thread( new ThreadStart(QueueMonitorfunc));     QueueMonitorThread.Start();     //代理程式更新TreeView,BeginInvoke     onTreeViewElement = new ThreadEventDelegate(populateTreeView);} 下面是線程的執行方法。public void QueueMonitorfunc(){     while( true)     {         if(isAbort())//判斷線程是否跳出迴圈,結束線程         {              break;         }         Object o = req_queue.getFile();//從隊列擷取檔案         if( (o  is FileInfo ))//隊列是否為空白         {              FileInfo f = (FileInfo)req_queue.getFile();              string filename = f.fName;              parse(f);//啟動一個線程處理              req_queue.remove();//從隊列中移出檔案         }         Thread.Sleep(500);     }}請注意上面的QueueMonitorThread線程,他自己不處理檔案。只是檢測隊列,如果有檔案存在就調用parse方法,而parse方法為每個檔案處理產生一個線程。方法內容如下:private void parse(FileInfo info){              //返回一個線程     Thread t = parserThread.CreateThread (new parserThread.Start(parserMethod), info);     t.Start ();     //阻塞調用線程     t.Join (Timeout.Infinite); }下面是建立線程的類:public class parserThread{     //代理代參數的方法     public delegate void Start (object obj);     //這個類用來解決ThreadStart只能代理無參數無傳回值函數而設計。     private class Argument     {         public object obj1;//用來儲存檔案名稱資料         public Start s1;         //建立該方法是為了由ThreadStart來代理,         public void parse()         {               s1(obj1);          }     }     //建立返回線程。     public static Thread CreateThread (Start s, Object arg1)     {         Argument arg = new Argument();         arg.obj1 = arg1;         arg.s1 = s;         Thread t = new Thread (new ThreadStart (arg.parse));         return t;     }}下面是parserMethod方法:public  void parserMethod(object obj){     FileInfo fInfo = (FileInfo)obj;     process_xml((fInfo.fName));}如果你看了ParserThread類的CreateThread方法,那上面的parserMethod方法就很清楚了。我們成功的完成了參數的傳遞。下面是process_xml方法:public  void process_xml(String name){     try     {         XmlDocument doc = new XmlDocument();         String fname = name;         doc.Load(fname);         XmlNodeList nList1;         XmlNodeList nList2;         XmlNodeList nList;         nList=doc.GetElementsByTagName("EmpDataSet");         for( int m =0;m         {              XmlElement element_main = (XmlElement)nList.Item(m);//emp_table              nList1 = element_main.ChildNodes ;//Emps              for( int k =0;k              {                   XmlElement element_fchild = (XmlElement)nList1.Item(k);                   nList2 = element_fchild.ChildNodes ;                   IEmpDetails emp = new EmpDetails();                   if( m_bAbort)                   {                       return;                   }                   for( int j =0;j                   {                       XmlElement child_element = (XmlElement)nList2.Item(j);                       if( child_element.Name == "Emp_id" )                       {                            emp.empId = System.Convert.ToInt32(child_element.InnerText);                        }                       if( child_element.Name == "Emp_Name" )                       {                            emp.empName = child_element.InnerText;                       }                       if( child_element.Name == "Emp_Address" )                       {                            emp.empAddress = child_element.InnerText;                       }                       if( child_element.Name == "Emp_City" )                       {                            emp.empCity = child_element.InnerText;                       }                       if( child_element.Name == "Emp_State" )                       {                            emp.empState = child_element.InnerText;                       }                       if( child_element.Name == "Emp_Pin" )                       {                            emp.empPin = child_element.InnerText;                       }                       if( child_element.Name == "Emp_Country" )                       {                            emp.empCountry = child_element.InnerText;                       }                       else if( child_element.Name == "Emp_Email" )                       {                            emp.empEmail = child_element.InnerText;                       }                    }                   //切換線程到TreeView所被建立的線程,從而更新TreeView,不過這裡是非同步。                   BeginInvoke(onTreeViewElement, new object[] {this, new ThreadEventArgs(emp)});              }         }     }     catch(Exception exp)     {         MessageBox.Show("Error...in displaying treeview "+exp.Message);     }}EmpDetails類實現了IEmpDetails介面,用來包含資料,略。BeginInvoke方法非同步執行,裡面通過代理onTreeViewElement來調用populateTreeView方法:private void populateTreeView(object sender, ThreadEventArgs e){     IEmpDetails ex = e.empDetails;     TreeNode n = new TreeNode("EMP :"+ex.empId);     n.Nodes.Add(ex.empName);     n.Nodes.Add(ex.empAddress);     n.Nodes.Add(ex.empCity);     n.Nodes.Add(ex.empState);     n.Nodes.Add(ex.empPin);     n.Nodes.Add(ex.empCountry);     n.Nodes.Add(ex.empEmail);     treeView1.Nodes.Add(n);}另外一個就是參數類,用來傳輸xml檔案的內容:public class ThreadEventArgs : EventArgs{     IEmpDetails _empDetails;     public IEmpDetails empDetails      {         get{ return _empDetails;}     }     public ThreadEventArgs(IEmpDetails empDetails)     {         this._empDetails = empDetails;     }} 結論:這個例子裡面的設計對於顯示大量的檔案是很有用的。這裡又一個限制就是一旦點擊了終止按紐,監視線程就會終止。要使能夠再次使用需要重其應用程式。希望這篇文章裡面的一些思想對你會有所協助(帶參數調用線程和建立多線程任務)。

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.