2012-03-05 78 views
0

我有文件傳輸應用程序(服務器端)TCP [.NET 4] 爲什麼BackgroundWorker的給我(backgroundWorker1_ProgressChanged)異常backgroundworker在ProgressChanged時會出現交叉線程異常?

客戶端發送一個包含目標路徑(其中文件應保存命令成)和大小的文件到服務器開始接收該文件..所以一旦服務器採用的命令..它會調用:

fileTransfer1.Receive(destPath, fileSize); 

這種方法在運行在Form1.cs自己的線程:

private void Job(object o) 
    { 

     Socket client = (Socket)o; 
     NetworkStream stream = new NetworkStream(client); 
     StreamReader sr = new StreamReader(stream); 

     string cmd = null; 

     while ((cmd = sr.ReadLine()) != null) 
     { 
      string[] command = cmd.Split('<'); 
      switch (command[0]) 
      { 
       case "receive": 
          fileTransfer1.Receive(command[1], Convert.ToInt64(command[2])); 
          break; 
          default: 
          break; 
      } 
     } 

fileTransfer1(用戶控件)

public void Receive(string destPath, long fileSize) 
    { 
      List<object> job = new List<object>(); 
      job.Add(destPath); 
      job.Add(fileSize); 
      backgroundWorker1.RunWorkerAsync(job); 
    } 

    long sum = 0; 
    long fileSize = 0; //this will equal the size of the file later. 
    private void ReceiveFile(string destPath, long fileSize) 
    { 
     using (fs = new FileStream(destPath, FileMode.Create, FileAccess.Write)) 
     { 
      try 
      { 
       int count = 0; 
       data = new byte[packetSize]; 
       while (sum < fileSize) 
       { 
        count = network.Read(data, 0, packetSize); 
        fs.Write(data, 0, count); 
        sum += count; 
        backgroundWorker1.ReportProgress((int)((sum * 100)/fileSize)); 
       } 
      } 
      finally 
      { 
       CloseTransfer(); 
      } 
     } 
    } 

這裏的BackgroundWorker的方法:

private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e) 
    { 
     List<object> job = (List<object>)e.Argument; 
     string destPath = (string)job[1]; 
     long fileSize = (long)job[2]; 
     ReceiveFile(destPath, fileSize); 
    } 

    private void backgroundWorker1_ProgressChanged(object sender, ProgressChangedEventArgs e) 
    { 
     progressBarFile.Position = e.ProgressPercentage; 
     progressBarFile.Text = progressBarFile.Position.ToString() + "%"; 
    /*here*/ labelRemaining.Text = CnvrtUnit(fileSize - sum); 
    } 

我的問題,我得到了一個異常(跨線程操作無效:控制 'labelRemaining'從其創建的線程以外的線程訪問。) 引用此行:

labelRemaining.Text = CnvrtUnit(fileSize - sum); 

我知道這個異常,我知道我必須使用(委託/調用)的事情..但..我知道backgroundworker意味着這.. ..加..我有相同的代碼,但服務器這裏發送一個文件給客戶端..它並沒有給出這個例外..它工作正常,表格顯示我的細節,因爲它應該是。
那麼,爲什麼我只是當我收到一個文件時得到這個異常?
注意:接收方法工作正常。

+0

哪個表單託管BackgroundWorker?是否有Chrome瀏覽器或IE顯示的「下載進度」彈出窗口? – 2012-03-05 18:56:46

+0

@ChrisShain不接受它在該主表單中的userControl ..它接收文件並顯示接收進度。 – 2012-03-05 18:58:05

+0

n/m在這個例外中無關緊要。 – Stephen 2012-03-05 19:03:51

回答

0

我已經想通了這一點

,因爲我的命令接收方法虛空工作(對象o)是一個線程下運行..所以這樣的:

case "receive": 
      fileTransfer1.Receive(command[1], Convert.ToInt64(command[2])); 
      break; 

也運行在同一個線程..這意味着代碼的其餘部分也運行在該線程.. 所以我只是改變了這一行這樣的:

case "receive": 
     Action a =() => fileTransfer1.Receive(command[2], Convert.ToInt64(command[3])); 
     Invoke(a); 
     break; 

現在UI線程將被通知運行其餘的接收代碼..這解決了我的問題。

2

由於backgroundWorker1_ProgressChanged()運行在與創建labelRemaining控件的線程不同的線程上,因此您正在獲取該錯誤。假設您創建的主UI線程上labelRemaining控制,你需要:

  • 從主線程執行backgroundWorker1.RunWorkerAsync(job)

  • backgroundWorker1_ProgressChanged,使用調度程序作爲described here

更新執行改變你labelRemaining對象在主線程: 我看到你正在使用的WinForms,而不是WPF。而不是使用分派這應該爲你工作:How to update the GUI from another thread in C#?

+0

我認爲你可能是正確的..因爲在接收案例..從客戶端接收命令的方法是在一個線程中運行,然後它在接收命令的同一個線程中調用backgroundworker.runasync()..這就是爲什麼我得到這個異常? – 2012-03-05 19:15:12

+0

我很確定這是爲什麼。否則,你不會從BackgroundWorker獲取該異常。 – 2012-03-05 19:16:44

+0

問題解決.. – 2012-03-05 19:31:28