![](/img/trans.png)
[英]Do I need to use invoke in backgroundworker progresschanged event?
[英]How do I use the WebClient progresschanged event from within backgroundworker dowork event?
我有这个代码:
int countfiletodownload = 0;
bool processStatus = false;
private void Parseanddownloadfiles()
{
downloadhtml(mainurl);
if (bgw.CancellationPending == false)
{
backgroundWorker1.ReportProgress(0, "Parsing Links");
HtmlAgilityPack.HtmlWeb hw = new HtmlAgilityPack.HtmlWeb();
HtmlAgilityPack.HtmlDocument doc = new HtmlAgilityPack.HtmlDocument();
doc = hw.Load(path_exe + "\\page.html");
foreach (HtmlAgilityPack.HtmlNode link in doc.DocumentNode.SelectNodes("//a[@href]"))
{
string hrefValue = link.GetAttributeValue("href", string.Empty);
if (hrefValue.Contains("US"))
{
string url = "http://www.mytests.com;
parsedlinks.Add(url);
if (bgw.CancellationPending == true)
return;
}
}
countfiletodownload = parsedlinks.Count;
backgroundWorker1.ReportProgress(0, "Downloading Files");
processStatus = true;
for (int i = 0; i < parsedlinks.Count && bgw.CancellationPending == false; i++)
{
try
{
using (WebClient client = new WebClient())
{
client.DownloadFileCompleted += client_DownloadFileCompleted;
client.DownloadProgressChanged += client_DownloadProgressChanged;
sw.Start();
Uri uri = new Uri(parsedlinks[i]);
string filename = parsedlinks[i].Substring(71);
client.DownloadFileAsync(uri, filesdirectory + "\\" + filename);
string filenametoreport = filename.Substring(1);
countfiletodownload--;
backgroundWorker1.ReportProgress(countfiletodownload, filenametoreport);
}
}
catch (Exception err)
{
string error = err.ToString();
}
}
}
}
void client_DownloadProgressChanged(object sender, DownloadProgressChangedEventArgs e)
{
// Calculate download speed and output it to labelSpeed.
label12.Text = string.Format("{0} kb/s", (e.BytesReceived / 1024d / sw.Elapsed.TotalSeconds).ToString("0.00"));
// Update the progressbar percentage only when the value is not the same.
progressBar1.Value = e.ProgressPercentage;
// Show the percentage on our label.
label13.Text = e.ProgressPercentage.ToString() + "%";
// Update the label with how much data have been downloaded so far and the total size of the file we are currently downloading
label14.Text = string.Format("{0} MB's / {1} MB's",
(e.BytesReceived / 1024d / 1024d).ToString("0.00"),
(e.TotalBytesToReceive / 1024d / 1024d).ToString("0.00"));
}
void client_DownloadFileCompleted(object sender, AsyncCompletedEventArgs e)
{
// Reset the stopwatch.
sw.Reset();
if (e.Cancelled == true)
{
MessageBox.Show("Download has been canceled.");
}
else
{
MessageBox.Show("Download completed!");
}
}
我正在注册 WebClient 的两个事件,DownloadFileCompleted 和 DownloadProgressChanged。
方法 Parseanddownloadfiles() 正在从 backgroundworker dowork 事件中调用:
BackgroundWorker bgw;
private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
{
bgw = (BackgroundWorker)sender;
if (bgw.CancellationPending == true)
{
return;
}
else
{
Parseanddownloadfiles();
}
}
一旦我向客户端添加了两个事件,我在第一行的 client_DownloadProgressChanged 事件中得到一个异常:
label12.Text = string.Format("{0} kb/s", (e.BytesReceived / 1024d / sw.Elapsed.TotalSeconds).ToString("0.00"));
跨线程操作无效:控制“label12”从创建它的线程以外的线程访问
我应该如何解决这个异常?
要对 UI 元素进行跨线程调用,您可以设置和使用调用委托。 此示例仅针对一个标签。 所有其他控件都必须具有类似的方法。
//Create a delegate for the call
public delegate void VoidStringDelegate(string str);
public void UpdateLabel12(string LabelText)
{
if (!label12.InvokeRequired)
{//If on the same thread directly change the value
label12.Text = LabelText;
}
else
{//If on a separate thread make an invoke call to this method from the correct thread
label12.Invoke(new VoidStringDelegate(UpdateLabel12), LabelText);
}
}
将“有问题”的行更改为:
label12.BeginInvoke((Action)(() => label12.Text = string.Format("{0} kb/s", (e.BytesReceived / 1024d / sw.Elapsed.TotalSeconds).ToString("0.00")));
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.