繁体   English   中英

我如何在 backgroundworker dowork 事件中使用 WebClient progresschanged 事件?

[英]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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM