【问题标题】:Why when downloading images the progressBar never get to 100% and i'm getting out of range exception?为什么在下载图像时,progressBar 永远不会达到 100% 并且我超出范围异常?
【发布时间】:2016-12-29 06:42:04
【问题描述】:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.IO;
using System.Net;
using System.Threading;

namespace SatelliteImages
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();

            ExtractImages ei = new ExtractImages();
            ei.Init();

            progressBar1.Minimum = 0;
            progressBar1.Maximum = 100;

            backgroundWorker1.RunWorkerAsync();
        }



        private void Form1_Load(object sender, EventArgs e)
        {

        }

        private void button1_Click(object sender, EventArgs e)
        {

        }

        private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
        {
            BackgroundWorker worker = sender as BackgroundWorker;

            for (int i = 0; i <= ExtractImages.imagesUrls.Count(); i++)
            {
                if (worker.CancellationPending == true)
                {
                    e.Cancel = true;
                    break;
                }
                else
                {
                    using (var client = new WebClient())
                    {
                        client.DownloadFile(ExtractImages.imagesUrls[i], @"C:\Temp\TestingSatelliteImagesDownload\" + i + ".jpg");
                        worker.ReportProgress(100 * i / ExtractImages.imagesUrls.Count());
                    }
                }
            }
        }

        private void backgroundWorker1_ProgressChanged(object sender, ProgressChangedEventArgs e)
        {
            progressBar1.Value = e.ProgressPercentage;
            label2.Text = (e.ProgressPercentage.ToString() + "%");
        }

        private void backgroundWorker1_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
        {
            if (e.Error == null)
            {
                MessageBox.Show("Completed without any errors");
            }
            else
            {
                string myerr = e.Error.ToString();
            }
        }
    }
}
  1. 为什么progressBar1 达到99% 并停在那里然后到达完成的事件?我怎样才能让它达到 100%?

  2. 我计算 reportProgress 和从 i = 0 开始的 FOR 循环的方式是否正常?

  3. 如何在表单上显示新标签(例如 label3)并显示剩余要下载的文件数?例如,如果在 imagesUrls 中有 399 个项目(要下载的文件),那么在 label3 中,我希望在每次文件下载完成并被访问时看到一个从 399 到 0 或 1 的计数器。

  4. 当它现在到完成的事件时,我得到了异常:

e.Error = {"索引超出范围。必须为非负数且小于 集合的大小。\r\n参数名称:索引"}

在 System.ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument 参数,ExceptionResource 资源)在 System.Collections.Generic.List`1.get_Item(Int32 索引)在 SatelliteImages.Form1.backgroundWorker1_DoWork(对象发送者, DoWorkEventArgs e) 在 D:\C-Sharp\SatelliteImages\SatelliteImages\SatelliteImages\Form1.cs:line 60 在 System.ComponentModel.BackgroundWorker.OnDoWork(DoWorkEventArgs e)
在 System.ComponentModel.BackgroundWorker.WorkerThreadStart(对象 论据)

我尝试过的更新:

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.IO;
using System.Net;
using System.Threading;

namespace SatelliteImages
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();

            ExtractImages ei = new ExtractImages();
            ei.Init();
        }



        private async void Form1_Load(object sender, EventArgs e)
        {
            label1.Text = "0 %";
            progressBar1.Minimum = 0;
            progressBar1.Maximum = ExtractImages.imagesUrls.Count() - 1;
            await DoWork();
        }

        private async Task DoWork()
        {
            for (int i = 0; i < ExtractImages.imagesUrls.Count(); i++)
            {
                using (var client = new WebClient())
                {
                    await client.DownloadFileTaskAsync(ExtractImages.imagesUrls[i], @"C:\Temp\TestingSatelliteImagesDownload\" + i + ".jpg");

                    progressBar1.Value = i + 1;
                    double average = (double)(i + 1) / ExtractImages.imagesUrls.Count();
                    label1.Text = (Math.Round(average, 1) * 100).ToString() + " %";
                }
            }
        }

        private void button1_Click(object sender, EventArgs e)
        {

        }
    }
}
  1. progressBar 没有走到尽头,它停在 99% 我认为是 99%。

  2. label1 最终显示 100%,但 progressBar 没有到达末尾。

  3. 最后我也遇到了异常:

例外是在Program.cs就行了:

Application.Run(new Form1());

附加信息:调用的目标已抛出异常。

System.Reflection.TargetInvocationException was unhandled
  HResult=-2146232828
  Message=Exception has been thrown by the target of an invocation.
  Source=mscorlib
  StackTrace:
       at System.RuntimeMethodHandle.InvokeMethod(Object target, Object[] arguments, Signature sig, Boolean constructor)
       at System.Reflection.RuntimeMethodInfo.UnsafeInvokeInternal(Object obj, Object[] parameters, Object[] arguments)
       at System.Delegate.DynamicInvokeImpl(Object[] args)
       at System.Windows.Forms.Control.InvokeMarshaledCallbackDo(ThreadMethodEntry tme)
       at System.Windows.Forms.Control.InvokeMarshaledCallbackHelper(Object obj)
       at System.Threading.ExecutionContext.RunInternal(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx)
       at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx)
       at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state)
       at System.Windows.Forms.Control.InvokeMarshaledCallback(ThreadMethodEntry tme)
       at System.Windows.Forms.Control.InvokeMarshaledCallbacks()
       at System.Windows.Forms.Control.WndProc(Message& m)
       at System.Windows.Forms.Control.ControlNativeWindow.OnMessage(Message& m)
       at System.Windows.Forms.Control.ControlNativeWindow.WndProc(Message& m)
       at System.Windows.Forms.NativeWindow.DebuggableCallback(IntPtr hWnd, Int32 msg, IntPtr wparam, IntPtr lparam)
       at System.Windows.Forms.UnsafeNativeMethods.DispatchMessageW(MSG& msg)
       at System.Windows.Forms.Application.ComponentManager.System.Windows.Forms.UnsafeNativeMethods.IMsoComponentManager.FPushMessageLoop(IntPtr dwComponentID, Int32 reason, Int32 pvLoopData)
       at System.Windows.Forms.Application.ThreadContext.RunMessageLoopInner(Int32 reason, ApplicationContext context)
       at System.Windows.Forms.Application.ThreadContext.RunMessageLoop(Int32 reason, ApplicationContext context)
       at System.Windows.Forms.Application.Run(Form mainForm)
       at SatelliteImages.Program.Main() in D:\C-Sharp\SatelliteImages\SatelliteImages\SatelliteImages\Program.cs:line 19
       at System.AppDomain._nExecuteAssembly(RuntimeAssembly assembly, String[] args)
       at System.AppDomain.ExecuteAssembly(String assemblyFile, Evidence assemblySecurity, String[] args)
       at Microsoft.VisualStudio.HostingProcess.HostProc.RunUsersAssembly()
       at System.Threading.ThreadHelper.ThreadStart_Context(Object state)
       at System.Threading.ExecutionContext.RunInternal(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx)
       at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx)
       at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state)
       at System.Threading.ThreadHelper.ThreadStart()
  InnerException: 
       HResult=-2146233086
       Message=Value of '399' is not valid for 'Value'. 'Value' should be between 'minimum' and 'maximum'.
Parameter name: Value
       ParamName=Value
       Source=System.Windows.Forms
       StackTrace:
            at System.Windows.Forms.ProgressBar.set_Value(Int32 value)
            at SatelliteImages.Form1.<DoWork>d__2.MoveNext() in D:\C-Sharp\SatelliteImages\SatelliteImages\SatelliteImages\Form1.cs:line 46
         --- End of stack trace from previous location where exception was thrown ---
            at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
            at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
            at System.Runtime.CompilerServices.TaskAwaiter.GetResult()
            at SatelliteImages.Form1.<Form1_Load>d__1.MoveNext() in D:\C-Sharp\SatelliteImages\SatelliteImages\SatelliteImages\Form1.cs:line 35
         --- End of stack trace from previous location where exception was thrown ---
            at System.Runtime.CompilerServices.AsyncMethodBuilderCore.<>c.<ThrowAsync>b__6_0(Object state)
       InnerException: 

【问题讨论】:

  • 为什么不直接使用progressBar1.Maximum = ExtractImages.imagesUrls.Count() 并避免所有这些计算。是的,从 0 开始是正确的。您的目标是什么版本的 .NET 框架? 4.5 及更高版本?
  • @user3185569 我在这个项目 .net 4.5.2 中用作目标
  • @user3185569 用更新部分查看我更新的问题,请我也对您的解决方案发表评论。谢谢。
  • @MosesMeteor 请将最大值更改为 ExtractImages.imagesUrls.Count()。您不需要从中减去 1。然后你的代码应该可以工作。请尝试更新结果。

标签: c# .net winforms


【解决方案1】:

要修正您的答案,您需要在 for 循环中将 &lt;= 替换为 &lt;

现在您可以看到为什么async-await 模式很有用,代码像任何普通代码一样流动。检查以下与您的相同的简单程序:

public partial class Form1 : Form
{
    public Form1()
    {
        InitializeComponent();
    }

    private async void Form1_Load(Object sender, EventArgs e)
    {
        label1.Text = "0 %";
        progressBar1.Minimum = 0;
        progressBar1.Maximum = ExtractImages.imagesUrls.Count() - 1;
        await DoWork();
    }

    private async Task DoWork()
    {
        for (int i = 0; i < ExtractImages.imagesUrls.Count(); i++)
        {
            using (var client = new WebClient())
            {
                await client.DownloadFileTaskAsync(ExtractImages.imagesUrls[i], @"C:\Temp\TestingSatelliteImagesDownload\" + i + ".jpg");

                progressBar1.Value = i + 1;
                double average = (double)(i + 1) / ExtractImages.imagesUrls.Count();
                label1.Text = (Math.Round(average, 1) * 100).ToString() + " %";
            }
        }
    }
}

请注意,您可以使用 IProgress&lt;int&gt; 并将更新 UI 的代码与下载文件的代码解耦:

private async void Form1_Load(Object sender, EventArgs e)
{
    label1.Text = "0 %";
    var progress = new Progress<int>();
    progress.ProgressChanged += Progress_ProgressChanged;
    await DoWork(progress);
}

private void Progress_ProgressChanged(Object sender, Int32 e)
{
     progressBar1.Value = e + 1;
     double average = ((double)(e + 1) / (ExtractImages.imagesUrls.Count()));
     label3.Text = (Math.Round(average, 1) * 100).ToString() + " %";
}

然后你在下载文件后添加:

progress.Report(i);

【讨论】:

  • 我现在尝试了你的代码。最后,progressBar 没有达到 100%,而是接近尾声的 99%。 label1 显示 100%。所以这需要修复。一旦完成下载文件的整个过程,我也会遇到异常。 Program.cs 上有例外,我将用我所做的和例外来更新我的问题。
  • var 进度在 Form1_Load 中的另一件事,我无法从 Progress_ProgressChanged 事件中使用/调用它。其次,进度变量没有属性报告。所以我不能输入progress.Report(i);因为没有 Report 属性。如果您可以向我展示更新 progressBar1 label1 和 label3 的完整代码,那就太好了。谢谢。
【解决方案2】:

对于您的第 1、2 和第 4 个问题:

您正在从 0 循环到包括两边的计数(0 到

我怀疑您的计算是将除法结果四舍五入为整数。因此,首先将 i 乘以 100.0,然后执行除法。喜欢 (i*100.0)/(images_count)。

对于您的第三个要求:

请参考 MSDN 示例-https://msdn.microsoft.com/en-us/library/t9fzsyec(v=vs.110).aspx

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-07-01
    • 1970-01-01
    相关资源
    最近更新 更多