在ProgressChanged中,backgroundworker会给出跨线程异常吗?

时间:2012-03-05 18:49:45

标签: c# winforms exception backgroundworker multithreading

我有文件传输应用程序(服务器 - 客户端)TCP [.net 4] 为什么backgroundworker在(backgroundWorker1_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(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();
            }
        }
    }

这是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);

我知道那个异常并且我知道我必须使用(委托/调用)的东西..但是..我知道背景工作者意味着这个..加上..我有相同的代码,但服务器在这里发送一个文件到客户端..它没有给出该例外..它工作正常,表单显示了应该的详细信息 那么为什么我收到文件后会收到此异常?
注意:接收方法正常。

2 个答案:

答案 0 :(得分:2)

您收到该错误是因为backgroundWorker1_ProgressChanged()正在与创建labelRemaining控件的线程不同的线程上运行。假设您在主UI线程上创建了labelRemaining控件,则需要:

  • 从主线程执行backgroundWorker1.RunWorkerAsync(job)

  • backgroundWorker1_ProgressChanged内,使用Dispatcher对主线程上的labelRemaining对象执行更改described here

更新: 我看到你使用的是winforms而不是WPF。而不是使用Dispatcher,这应该适合您:How to update the GUI from another thread in C#?

答案 1 :(得分:0)

我已经想出了

因为我的命令接收方法 Void Job(对象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-Thread运行其余的接收代码..这解决了我的问题。