Search code examples
c#winformsexceptionbackgroundworkermultithreading

backgroundworker gives a cross-thread exception when ProgressChanged?


i have file transfer application (Server-Client) TCP [.net 4] why is backgroundworker gives me an exception in (backgroundWorker1_ProgressChanged)

The client send command that has a destination path (where file should saved into) and the size of file to the Server to start receiving that file .. so once the server takes that command .. it will call :

fileTransfer1.Receive(destPath, fileSize);

this method run in its own thread in 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 (userControl) :

    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();
            }
        }
    }

here's backgroundworker method :

    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);  
    }

my problem that i got an exception (Cross-thread operation not valid: Control 'labelRemaining' accessed from a thread other than the thread it was created on.) that references to this line:

 labelRemaining.Text = CnvrtUnit(fileSize - sum);

i know about that exception and i know that i have to use (delegate/invoke) thing .. but.. i know that backgroundworker meant for this .. plus .. i have the same code but The server here Send a file to the client .. and it doesn't give that exception .. it works fine and the form shows me the details as it should be.
So why do i get this exception just when i receive a file ??
note : receive method works fine.


Solution

  • i've figured that out

    since my command receiver method Void Job(object o) is running under a thread .. so this:

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

    also runs in the same thread .. that means the rest of the code also runs in that thread .. so i just changed this line to this:

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

    now UI-Thread will be notified to run the rest of the receiving code .. which solved my problem.