2011-05-09 16 views
2

我有一個非常簡單的形式與一個按鈕,激發我創建的一個從ActiveDirectory收集數據並將其添加到Excel工作表。VB.NET - 在單獨的線程中工作,以防止掛起形式

問題是,當我點擊這個按鈕時,整個表單都會掛起。所以我認爲收集數據並將其添加到Excel工作表的操作應該在它自己的線程中運行,以便表單不會掛起。可能還會增加一個進度條。 但是,進度條位於運行項目後啓動的主用戶窗體中。

爲了按照我想要的方式獲得此功能,我需要做些什麼?

編輯:添加了一些我的代碼。我有一個MainForm.vb和一個CodeFile.vb。 我希望CodeFile.vb中的大部分代碼更整潔。

MainForm.vb

Imports User_edit.CodeFile 
Imports System.ComponentModel 

Public Class MainForm 
    Private Sub btnImportData_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnImportData.Click 
     If MyBackgroundWorker.IsBusy <> True Then 
      MyBackgroundWorker.RunWorkerAsync() 
     End If 
    End Sub 

    Private Sub BackgroundWorker_DoWork(ByVal sender As System.Object, ByVal e As System.ComponentModel.DoWorkEventArgs) Handles MyBackgroundWorker.DoWork 
     ExportADUsers() 
    End Sub 

    Private Sub BackgroundWorker_ProgressChanged(ByVal sender As System.Object, ByVal e As System.ComponentModel.ProgressChangedEventArgs) Handles MyBackgroundWorker.ProgressChanged 
     statusBarLabel.Text = (e.ProgressPercentage.ToString) 
    End Sub 

    Private Sub BackgroundWorker_RunWorkerCompleted(ByVal sender As System.Object, ByVal e As System.ComponentModel.RunWorkerCompletedEventArgs) Handles MyBackgroundWorker.RunWorkerCompleted 
     statusBarLabel.Text = "Finished" 
    End Sub 
End Class 

CodeFile.vb

Imports System.DirectoryServices 
Imports System.ComponentModel 
Imports System.Threading 

Module CodeFile 
    Public Sub ExportADUsers() 
     MainForm.MyBackgroundWorker.WorkerReportsProgress = True 
     MainForm.MyBackgroundWorker.WorkerSupportsCancellation = True 

     Dim i As Integer 

     Dim objRootDSE, strRoot, strfilter, strAttributes, strScope 
      objRootDSE = GetObject("LDAP://RootDSE") 
      strRoot = objRootDSE.GET("DefaultNamingContext") 
      strfilter = "(&(objectCategory=Person)(objectClass=User))" 
      strAttributes = "mail,userPrincipalName,givenName,sn," & _ 
       "initials,displayName,physicalDeliveryOfficeName," & _ 
       "telephoneNumber,mail,wWWHomePage,profilePath," & _ 
       "scriptPath,homeDirectory,homeDrive,title,department," & _ 
       "company,manager,homePhone,pager,mobile," & _ 
       "facsimileTelephoneNumber,ipphone,info," & _ 
       "streetAddress,postOfficeBox,l,st,postalCode,c" 
      'Scope of the search. Change to "onelevel" if you didn't want to search child OU's 
      MainForm.statusBarLabel.Text = "Collecting data" 
     strScope = "subtree" 

      Dim cn, cmd, rs 
      cn = CreateObject("ADODB.Connection") 
      cmd = CreateObject("ADODB.Command") 

      cn.open("Provider=ADsDSOObject;") 
      cmd.ActiveConnection = cn 
      cmd.commandtext = "<LDAP://" & strRoot & ">;" & strfilter & ";" & _ 
           strAttributes & ";" & strScope 

      rs = cmd.EXECUTE 

      Dim objExcel, objWB, objSheet 

      objExcel = CreateObject("Excel.Application") 
      objWB = objExcel.Workbooks.Add 
     objSheet = objWB.Worksheets(1) 

     For i = 0 To rs.Fields.Count - 1 
      MainForm.MyBackgroundWorker.ReportProgress(i * 10) 
      objSheet.Cells(1, i + 1).Value = rs.Fields(i).Name 
      objSheet.Cells(1, i + 1).Font.Bold = True 
     Next 

      Dim strExportFile 
      strExportFile = "C:\users\vsando\desktop\export.xls" 

      objSheet.Range("A2").CopyFromRecordset(rs) 
      objSheet.SaveAs(strExportFile) 

      'Clean up 
      rs.Close() 
      cn.Close() 
      objSheet = Nothing 
      objWB = Nothing 
      objExcel.Quit() 
      objExcel = Nothing 

    End Sub 

通知的ExportFromAD子,我在CodeFile.vb了。這是實際上正在做的工作。在每個將數據添加到Excel的循環中,我已經放置了MainForm.MyBackgroundWorker.ReportProgress(i * 10)

問題是,它實際上並沒有更新表單上的標籤。我發現這很奇怪,因爲表單並沒有真正懸掛或任何東西。它試圖訪問一個不同的線程或東西?意思是,表單是在它自己的線程上運行的,無法從我的第二個線程訪問它?

+1

你已經在你的標籤中得到了答案:最簡單的方法是使用'BackgroundWorker'組件。 [MSDN上的示例實現](http://msdn.microsoft.com/zh-cn/library/system.componentmodel.backgroundworker.aspx)已經非常好。 – 2011-05-09 11:31:44

+0

從示例代碼:'If(worker.CancellationPending = True)Then' ... yuck!然而,他們再次讓實習生寫下榜樣。 – 2011-05-09 11:33:28

+0

@Konrad:Yuck,我同意。但更有可能的是,他們妄圖「澄清」代碼。 – 2011-05-09 11:49:48

回答

3

最好的辦法是使用BackgroundWorker,因爲這個類是爲這個精確的用例設計的。

這也允許你call back to the form to update the status bar

+0

請參閱更新的主題。我嘗試添加背景工作者。我認爲它正在工作,但我無法獲得進度條或statusstrip標籤實際更新。我嘗試添加一個斷點來查看運行時標籤的實際值。事實上它已經確立。它只是不顯示。這就是爲什麼我認爲它試圖顯示不同線程上的標籤? – 2011-05-09 12:37:01

2

BackgroundWorker類是你需要使用的。要將數據傳回表單的進度條,請將WorkerReportsProgress屬性設置爲true,並處理ProgressChanged事件以設置進度欄的值。從長期運行的方法,你可以發送像這樣的進展:

backgroundworker.ReportProgress(10)