【问题标题】:Update label.text with backgroundworker while downloading file下载文件时使用 backgroundworker 更新 label.text
【发布时间】:2014-02-08 23:38:27
【问题描述】:

这是我当前的后台工作代码,我想得到标签来说明它正在下载哪个文件。

private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
{
    string[] FileArray = new string[] {
                "configs.pck", "interfaces.pck", "trees.pck", "elementskill.dll",
                "reportbugs\\zreportbugs.exe", "userdata\\server\\serverlist.txt",
                "userdata\\systemsettings.ini", "data\\aipolicy.data", "data\\domain.data",
                "data\\domain1.data", "data\\domain2.data", "data\\domain3.data",
                "data\\domain4.data", "data\\dyn_tasks.data", "data\\dynamicobjects.data", "data\\elements.data",
                "data\\forbidden_task.txt", "data\\gshop.data", "data\\gshop1.data", "data\\gshop2.data",
                "data\\hometowndata", "data\\path.data", "data\\task_npc.data", "data\\tasks.data",
                "data\\tasks.data1", "data\\tasks.data2", "data\\tasks.data3", "data\\tasks.data4",
                "data\\tasks.data5", "data\\tasks.data6", "data\\tasks.data7", "data\\tasks.data8",
                "data\\tasks.data9", "data\\tasks.data10", "data\\tasks.data11", "data\\tasks.data12",
                "data\\tasks.data13", "data\\tasks.data14", "data\\tasks.data15", "data\\tasks.data16",
                "data\\tasks.data17", "data\\tasks.data18", "data\\tasks.data19", "data\\tasks.data20",
                "data\\tasks.data21", "data\\tasks.data22", "data\\tasks.data23", "data\\tasks.data24",
                "data\\tasks.data25", "data\\tasks.data26", "data\\tasks.data27", "data\\tasks.data28",
                "data\\tasks.data29", "data\\tasks.data30", "data\\tasks.data31", "data\\tasks.data32",
                "data\\tasks.data33", "data\\tasks.data34", "data\\tasks.data35", "data\\tasks.data36",
                "data\\tasks.data37", "data\\tasks.data38", "data\\tasks.data39", "data\\tasks.data40",
                "data\\tasks.data41", "data\\tasks.data42", "data\\tasks.data43", "data\\tasks.data44",
                "data\\title_def.lua", "data\\title_def_u.lua", "data\\VIPAward.data"};

    foreach (string FileName in FileArray)
    {
        // The URL to download the file from
        string sUrlToReadFileFrom = "http://jd.paradise-gaming.org/Update/element/" + FileName;

        // The path to write the file to
        string sFilePathToWriteFileTo = Application.StartupPath + "\\element\\" + FileName;

        // First, we need to get the exact size (in bytes) of the file we are downloading
        Uri url = new Uri("http://jd.paradise-gaming.org/Update/element/" + FileName);
        System.Net.HttpWebRequest request = (System.Net.HttpWebRequest)System.Net.WebRequest.Create(url);
        System.Net.HttpWebResponse response = (System.Net.HttpWebResponse)request.GetResponse();
        response.Close();

        // Get last time file was modified
        FileSize = response.LastModified;

        string LatestWriteTime = Application.StartupPath + "\\element\\" + FileName; //Get most recent time file was saved.
        DateTime UserGshop = File.GetLastWriteTime(LatestWriteTime);
        UserFileTime = UserGshop;
        if (UserFileTime < FileSize)
        {
            // Gets the size of the file in bytes
            Int64 iSize = response.ContentLength;

            // Keeps track of the total bytes downloaded so we can update the progress bar
            Int64 iRunningByteTotal = 0;

            // Use the webclient object to download the file
            using (System.Net.WebClient client = new System.Net.WebClient())
            {
                // Open the file at the remote URL for reading
                using (System.IO.Stream streamRemote = client.OpenRead(new Uri(sUrlToReadFileFrom)))
                {
                    // Using the FileStream object, we can write the downloaded bytes to the file system
                    Directory.CreateDirectory(Path.GetDirectoryName(sFilePathToWriteFileTo));
                    using (Stream streamLocal = new FileStream(sFilePathToWriteFileTo, FileMode.Create))
                    {
                        // Loop the stream and get the file into the byte buffer
                        int iByteSize = 0;
                        byte[] byteBuffer = new byte[iSize];
                        while ((iByteSize = streamRemote.Read(byteBuffer, 0, byteBuffer.Length)) > 0)
                        {
                            // Write the bytes to the file system at the file path specified
                            streamLocal.Write(byteBuffer, 0, iByteSize);
                            iRunningByteTotal += iByteSize;

                            // Calculate the progress out of a base "100"
                            double dIndex = (double)(iRunningByteTotal);
                            double dTotal = (double)byteBuffer.Length;
                            double dProgressPercentage = (dIndex / dTotal);
                            int iProgressPercentage = (int)(dProgressPercentage * 100);

                            // Update the progress bar
                            backgroundWorker1.ReportProgress(iProgressPercentage);
                        }

                        // Clean up the file stream
                        streamLocal.Close();
                    }

                    // Close the connection to the remote server
                    streamRemote.Close();
                }
            }
        }
    }
}

private void backgroundWorker1_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
    pBarFileProgress.Value = e.ProgressPercentage;
    gbFileProgress.Text = String.Format("Current File Progress: {0} %", e.ProgressPercentage);
    lblCheckFile.Text = "Downloaing" + FileName;
}

private void backgroundWorker1_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
    btnPlay.Enabled = true;
    btnFullCheck.Enabled = true;
    lblCheckFile.Text = "Download Complete!";
    gbFileProgress.Text = "No More Files to Check!";
    pBarFileProgress.Value = 0;
}

我尝试在不同时间将lblCheckFile.Text = "Downloaing" + FileName; 放在 backgroundworker1_DoWork 和 Progress_Change 上,但 Progress_Change 只显示“正在下载”而不是文件名。当我把它放在 DoWork 下时,它会出错并说Exception:Thrown: "Cross-thread operation not valid: Control 'lblCheckFile' accessed from a thread other than the thread it was created on."

【问题讨论】:

  • ProgressChanged 是正确的地方。您确定处理程序实际上已附加/被调用吗?如果是这样,请将FileName 传递给继承自ProgressChangedEventArgs 的类中的处理程序,而不是直接使用它。
  • @GSerg 我该怎么做呢?
  • @Hulu8004 抱歉,没有继承。只需将文件名作为backgroundWorker1.ReportProgress 的第二个参数传递,然后使用(string)e.UserState 在ProgressChanged 中检索它。
  • 我已经编辑了你的标题。请参阅“Should questions include “tags” in their titles?”,其中的共识是“不,他们不应该”。

标签: c# multithreading backgroundworker


【解决方案1】:

DoWork 事件中的foreach 循环正在动态创建FileName 字符串以遍历FileArray 字符串数组。在该循环之外无法访问它,因此我不确定ProgressChanged 事件中的以下FileName 变量来自何处:

lblCheckFile.Text = "Downloaing" + FileName;

使用 BackgroundWorker 构造中内置的组件来报告进度。

来自您的DoWork 活动:

...
// use the webclient object to download the file
using (System.Net.WebClient client = new System.Net.WebClient())
{
    ...
    // pass the filename as the second argument (change 0 to the correct %)
    backgroundWorker1.ReportProgress(0, FileName);
    ...

在您的ProgressChanged 事件中,您将获得从e.UserState 传递的值:

var fileName = Convert.ToString(e.UserState);

lblCheckFile.Text = string.Format("Downloading {0}", fileName);

要完成这项工作,您必须删除当前调用:

backgroundWorker1.ReportProgress(iProgressPercentage);

把它和我的电话结合起来:

backgroundWorker1.ReportProgress(iProgressPercentage, FileName);

否则,您会在标签中短暂看到您的文件名,但随后通过iProgressPercentage 的第二个调用实际上将传递一个空值作为UserState,然后将转换为一个空值字符串并导致您的文件名从标签中消失。

【讨论】:

  • 这几乎解决了这个问题,但是当它说下载时,它后面没有“文件名”。它只是空白。
  • 它们都显示了正确的文件名,它只是我可以在一瞬间看到文件名,但它会消失,直到下一个文件正在下载,然后它就消失了。
  • 非常感谢!仅供参考,您可以在“1”BackgroundWorker 中传递多少个参数?
【解决方案2】:

在 Windows 窗体(和大多数其他 GUI 框架)中,您不能从后台线程执行 GUI 操作。这就是您收到的“跨线程操作无效”错误的含义。

为此,您需要使用 Invoke() / BeginInvoke() 方法在主 GUI 线程上进行标签更新。如果您的后台线程有表单句柄,它可以直接执行此操作。否则,常见的设计模式是让线程引发表单订阅的事件;然后表单的事件处理程序将使用 Invoke/BeginInvoke 更新 GUI 线程上的标签。

另请参阅this discussion of BackgroundWorkers updating GUIs,其中包含有关此解决方案和其他解决方案的更多信息。

【讨论】:

  • ProgressChanged 在 UI 线程上被调用,并且 OP 已经在正确的位置有代码。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多