【问题标题】:C# Backgroundworker download progress in label, get bytes in label标签中的C#Backgroundworker下载进度,获取标签中的字节
【发布时间】:2018-06-30 00:51:12
【问题描述】:

我创建了一个应用程序来修补我的游戏服务器文件。 但是,我有 3 个我无法解决的问题:

  1. 下载新补丁时,它不会立即更新进度条,而是在大约 30-40 秒后刷新
  2. 我想要一个标签来显示他们正在下载多少兆字节,以及他们到目前为止有多少(例如:122Mb/750Mb
  3. 下载时,我想要一个标签来显示到目前为止已下载量的 ~%

我不确定如何添加数字 2 和 3,数字 1 的问题似乎很荒谬,因为没有任何迹象表明它应该在我的编码中 30-40 秒后刷新(至少据我所知)

我的 backgroundWorker1_DoWork:

private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
    {
        //Defines the server's update directory
        string Server = "http://localhost/dl/game-updates/";

        //Defines application root
        string Root = AppDomain.CurrentDomain.BaseDirectory;

        //Make sure version file exists
        FileStream fs = null;
        if (!File.Exists("version"))
        {
            using (fs = File.Create("version"))
            {

            }

            using (StreamWriter sw = new StreamWriter("version"))
            {
                sw.Write("1.0");
            }
        }
        //checks client version
        string lclVersion;
        using (StreamReader reader = new StreamReader("version"))
        {
            lclVersion = reader.ReadLine();
        }
        decimal localVersion = decimal.Parse(lclVersion);

        //server's list of updates
        XDocument serverXml = XDocument.Load(@Server + "Updates.xml");

        //The Update Process
        foreach (XElement update in serverXml.Descendants("update"))
        {
            string version = update.Element("version").Value;
            string file = update.Element("file").Value;

            decimal serverVersion = decimal.Parse(version);


            string sUrlToReadFileFrom = Server + file;

            string sFilePathToWriteFileTo = Root + file;

            if (serverVersion > localVersion)
            {
                Uri url = new Uri(sUrlToReadFileFrom);
                System.Net.HttpWebRequest request = (System.Net.HttpWebRequest)System.Net.WebRequest.Create(url);
                System.Net.HttpWebResponse response = (System.Net.HttpWebResponse)request.GetResponse();
                response.Close();

                Int64 iSize = response.ContentLength;

                Int64 iRunningByteTotal = 0;

                using (System.Net.WebClient client = new System.Net.WebClient())
                {
                    using (System.IO.Stream streamRemote = client.OpenRead(new Uri(sUrlToReadFileFrom)))
                    {
                        using (Stream streamLocal = new FileStream(sFilePathToWriteFileTo, FileMode.Create, FileAccess.Write, FileShare.None))
                        {
                            int iByteSize = 0;
                            byte[] byteBuffer = new byte[iSize];
                            while ((iByteSize = streamRemote.Read(byteBuffer, 0, byteBuffer.Length)) > 0)
                            {
                                streamLocal.Write(byteBuffer, 0, iByteSize);
                                iRunningByteTotal += iByteSize;

                                double dIndex = (double)(iRunningByteTotal);
                                double dTotal = (double)byteBuffer.Length;
                                double dProgressPercentage = (dIndex / dTotal);
                                int iProgressPercentage = (int)(dProgressPercentage * 100);

                                backgroundWorker1.ReportProgress(iProgressPercentage);
                            }

                            streamLocal.Close();
                        }

                        streamRemote.Close();
                    }
                }

                //unzip
                using (ZipFile zip = ZipFile.Read(file))
                {
                    foreach (ZipEntry zipFiles in zip)
                    {
                        zipFiles.Extract(Root + "\\", true);
                    }
                }

                //download new version file
                WebClient webClient = new WebClient();
                webClient.DownloadFile(Server + "version.txt", @Root + "version");

                //Delete Zip File
                deleteFile(file);
            }
        }
    }

我的 backgroundWorker1_ProgressChanged:

private void backgroundWorker1_ProgressChanged(object sender, ProgressChangedEventArgs e)
    {
        progressBar1.Value = e.ProgressPercentage;
        label1.Text = "Downloading updates...";
    }

还有我的 backgroundWorker1_RunWorkerCompleted:

private void backgroundWorker1_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
    {
        settings_btn.Enabled = true;
        start_btn_disabled.Enabled = false;
        start_btn_disabled.Visible = false;
        start_btn.Visible = true;
        start_btn.Enabled = true;
        progressBar1.Value = 100;
        label1.Text = "Client is up to date!";
    }

另外,附注:我在更新 backgroundWorker2_DoWork 中的标签时也遇到了一些问题? 有什么想法吗?

【问题讨论】:

  • 欢迎来到这个网站,约翰。如果您想有更好的机会得到回答,请查看:stackoverflow.com/help/how-to-ask
  • @demonplus 该帖子上的那个人正在使用 backgroundworker 插入 mysql 值。我不是。在说它是重复的之前,您应该阅读该帖子
  • @JohnK 当有人建议重复时,这可能意味着该问题中的代码对您有用 - 我认为您采取了错误的方式。您的问题部分是关于在使用 BackgroundWorker 时更新标签,这与链接的问题相同。
  • 哦。我的错。对不起,@demonplus。

标签: c#


【解决方案1】:

这是一些使用 BackgroundWorker 更新 Form1 上的标签的工作代码。

创建一个新的 Windows 窗体项目并将其放入您的代码中,它就会工作。 它超级丑陋,但它有效。 之后,只需将您的代码插入 DoWork 方法并计算您的值并发送到 ReportProgress。

请记住,在 DoWork 方法中完成的工作是实际的后台线程。 这意味着在该方法 (DoWork) 中,您无法访问 UI(表单)元素,因为它们位于 UI 线程上。

 public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
            backgroundWorker1.DoWork += backgroundWorker1_DoWork;
            backgroundWorker1.ProgressChanged += backgroundWorker1_ProgressChanged;
            backgroundWorker1.WorkerReportsProgress = true;
            backgroundWorker1.RunWorkerCompleted += backgroundWorker1_RunWorkerCompleted;
        }

        void backgroundWorker1_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
        {
            button1.Enabled = true;
        }

        private void button1_Click(object sender, EventArgs e)
        {
            button1.Enabled = false;
            backgroundWorker1.RunWorkerAsync();
        }

        void backgroundWorker1_ProgressChanged(object sender, ProgressChangedEventArgs e)
        {
            label1.Text = e.ProgressPercentage.ToString();
        }

        void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
        {
            FakeCountingWork();
        }


        private void FakeCountingWork()
        {
            int totalNumber = 100;
            int progressCounter = 0;
            while (progressCounter < totalNumber)
            {
                int fakecounter = 0;
                for (int x = 0; x < 100000000; x++)
                {
                    fakecounter++;
                }
                progressCounter++;
                backgroundWorker1.ReportProgress(progressCounter);
            }
        }
    }
################################ 编辑添加其他功能

好的,下面将介绍如何实现一个显示目前已下载字节数的标签。 将名为 label2 的第二个标签添加到您的表单中。
接下来从我之前的示例中更改以下方法。 在这里,我们将使用 UserState 将额外的值传递给 ProgressChanged 事件。这很简单。您可以看到我正在生成一个随机数,它现在将出现在 Label2 中。这是您可以显示字节数的地方。

  void backgroundWorker1_ProgressChanged(object sender, ProgressChangedEventArgs e)
        {
            label1.Text = e.ProgressPercentage.ToString();
            label2.Text = e.UserState.ToString();
        }

 private void FakeCountingWork()
        {
            int totalNumber = 100;
            int progressCounter = 0;
            Random rnd = new Random();
            while (progressCounter < totalNumber)
            {
                int fakecounter = 0;
                for (int x = 0; x < 100000000; x++)
                {
                    fakecounter++;
                }
                progressCounter++;
               updateValue = rnd.Next();
              backgroundWorker1.ReportProgress(progressCounter,updateValue);
            }
        }

【讨论】:

  • 这就像一个魅力(显示百分比部分)谢谢!
  • @JohnK 我添加了实现 UserState 对象的附加功能,并将附加值传递给 ProgressChanged 事件,以向您展示如何使用另一个标签显示字节数。
  • 我不确定如何使用我的 int64 iSize 值进行这项工作,但是,我一定会尝试一下,谢谢!
【解决方案2】:

我想这是因为您试图在不同的线程上更新 UI 对象。如果使用 wpf,您是否尝试过使用 Dispatcher? https://msdn.microsoft.com/en-us/library/system.windows.threading.dispatcher.invoke(v=vs.110).aspx

如果使用 Winforms,还是调用? https://msdn.microsoft.com/fr-ca/library/zyzhdc6b(v=vs.85).aspx

编辑: 正如@daylight 指出的那样,UI 正在progresschanged 事件中进行更新,该事件在创建后台工作者的线程上执行,因此不应该存在关于线程的问题。请参阅https://msdn.microsoft.com/en-us/library/ka89zff4(v=vs.110).aspx 了解更多信息

【讨论】:

  • 我认为@demonplus 发布的链接会有所帮助。无论后台工作人员在做什么,它都是与 UI 对象所在的线程不同的线程,因此您不能像往常一样更新它们。
  • 实际上,他似乎只在 ProgressChanged 事件中正确更新了 UI 线程对象(标签)。使用 ProgressChanged 事件更新 UI 元素是正确的方法,您可以看到它在我更新表单标签的答案中有效。您只是无法从 DoWork() 方法访问 UI(表单)元素 --- 这是一个单独的执行线程并且会失败。
  • @daylight 非常正确,我没有想到这一点。对于任何想要确认这一点的人,文章msdn.microsoft.com/en-us/library/ka89zff4(v=vs.110).aspx 指出“ProgressChanged 事件处理程序在创建 BackgroundWorker 的线程上执行”。我是 StackOverflow 的新手,你建议我删除我的答案还是留下它?
  • 我喜欢你检查了我所说的并保持讨论的开放性。我认为您应该更新它并提及您发现了新信息。但我不是专家所以不确定。
猜你喜欢
  • 2015-07-01
  • 1970-01-01
  • 1970-01-01
  • 2016-06-11
  • 1970-01-01
  • 1970-01-01
  • 2021-05-13
  • 2019-12-21
  • 1970-01-01
相关资源
最近更新 更多