下载文件时用backgroundworker更新label.text

时间:2014-01-19 21:54:59

标签: c# multithreading backgroundworker

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

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."

2 个答案:

答案 0 :(得分:2)

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

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 :(得分:1)

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

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

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