我有文件传输应用程序(服务器 - 客户端)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);
我知道那个异常并且我知道我必须使用(委托/调用)的东西..但是..我知道背景工作者意味着这个..加上..我有相同的代码,但服务器在这里发送一个文件到客户端..它没有给出该例外..它工作正常,表单显示了应该的详细信息
那么为什么我收到文件后会收到此异常?
注意:接收方法正常。
答案 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运行其余的接收代码..这解决了我的问题。