Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/297.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C#进度条调用/委托问题_C#_Progress Bar - Fatal编程技术网

C#进度条调用/委托问题

C#进度条调用/委托问题,c#,progress-bar,C#,Progress Bar,我正在传输文件,希望有一个进度条来显示每个文件的实际进度。这对于15兆以下的文件来说效果很好,但大于15兆的文件似乎会导致我的应用程序冻结。如果我不为进度条调用此代码,这些较大的文件可以正常传输 我尝试了各种不同的方法来处理代表们的问题,但没有成功。相反,它们可以处理较小的文件,但不能处理较大的文件 一些成功的例子 pbFileProgress.Invoke((MethodInvoker) delegate { pbFileProgress.Value = args.

我正在传输文件,希望有一个进度条来显示每个文件的实际进度。这对于15兆以下的文件来说效果很好,但大于15兆的文件似乎会导致我的应用程序冻结。如果我不为进度条调用此代码,这些较大的文件可以正常传输

我尝试了各种不同的方法来处理代表们的问题,但没有成功。相反,它们可以处理较小的文件,但不能处理较大的文件

一些成功的例子

pbFileProgress.Invoke((MethodInvoker)
   delegate 
   { 
      pbFileProgress.Value = args.PercentDone;
   });                
此外,此方法集合适用于较小的文件

private delegate void SetProgressBarCallback(int percentDone);

public void UpdateProgressBar(object send, UploadProgressArgs args)
{
   if (pbFileProgress.InvokeRequired)
   {
      var d = new SetProgressBarCallback(ProgressBarUpdate);
      BeginInvoke(d, new object[] { args.PercentDone });
   }
   else
   {
      ProgressBarUpdate(args.PercentDone);
   }
}

public void ProgressBarUpdate(int percentDone)
{
   pbFileProgress.Value = percentDone;
}

但是,如果我尝试更大的文件,一切都会冻结。

您可以基于UI元素进行调用。例如:

private delegate void InvokeUpdateProgressBar(object send, UploadProgressArgs args);
private int _PercentDone = -1;

public void UpdateProgressBar(object send, UploadProgressArgs args)
{
   if(_PercentDone != args.PercentDone)
   {
      if (pbFileProgress.InvokeRequired)
      {
         pbFileProgress.Invoke(
            new InvokeUpdateProgressBar(UpdateProgressBar),
            new object[] { send, args });
      }
      else
      {
         ProgressBarUpdate(args.PercentDone);
      }
      _PercentDone = args.PercentDone;
   }
}
否则我会建议Aaron McIver做了什么,并使用这个类。 有关使用BackgroundWorker类更新progressbar的详细信息,请参见示例

更新
看来你不是唯一一个有这个问题的人。看这里。Kent还指出:
如果你读到S3论坛,你会发现很多人都有类似的问题

尽管缺乏背景,但下面的例子是有效的。BeginInvoke或Invoke方法最多只能调用100次

Task.Factory.StartNew(() =>
   {
      using (var source = File.OpenRead(@"D:\Temp\bbe.wav"))
      using (var destination = File.Create(@"D:\Temp\Copy.wav"))
      {
         var blockUnit = source.Length / 100;

         var total = 0L;
         var lastValue = 0;

         var buffer = new byte[4096];
         int count;

         while ((count = source.Read(buffer, 0, buffer.Length)) > 0)
         {
            destination.Write(buffer, 0, count);

            total += count;

            if (blockUnit > 0 && total / blockUnit > lastValue)
            {
               this.BeginInvoke(
                  new Action<int>(value => this.progressBar1.Value = value),
                  lastValue = (int)(total / blockUnit));
            }
         }

         this.BeginInvoke(
            new Action<int>(value => this.progressBar1.Value = value), 100);
      }
   });
Task.Factory.StartNew(()=>
{
使用(var source=File.OpenRead(@“D:\Temp\bbe.wav”))
使用(var destination=File.Create(@“D:\Temp\Copy.wav”))
{
var blockUnit=源长度/100;
var总计=0升;
var lastValue=0;
var buffer=新字节[4096];
整数计数;
而((count=source.Read(buffer,0,buffer.Length))>0)
{
写入(缓冲区,0,计数);
总数+=计数;
如果(区块单位>0&&total/blockUnit>lastValue)
{
这是我的开始(
新操作(value=>this.progressBar1.value=value),
lastValue=(int)(总/区块单位));
}
}
这是我的开始(
新操作(value=>this.progressBar1.value=value),100);
}
});

在后台线程和前台线程之间通信时,此问题非常常见:后台线程向前台线程发送的更新太多

前台线程处理更新、绘图和用户输入,因此当出现太多更新时,UI会冻结,试图跟上进度。
显然,如果后台线程继续发送更新,即使后台任务完成,前台也可以备份

这个问题有几种解决方案,但我最强烈的建议是在前台线程中使用
计时器
,以轮询后台进程并更新UI。
使用
计时器的优点是:

  • 后台线程可以根据需要随时报告进度
  • 前台线程可以放松,直到需要更新
  • 前台线程不会使用更新“备份”
  • 如果前台线程处于“静止”状态,那么后台线程将获得更多的处理器时间
  • 定时器的频率可以设置为一个“合理”的值,例如250ms(每秒4次更新),这样可以使进程平稳,但不会占用整个处理器

与往常一样,在线程之间通信进度时,线程安全性非常重要。在这种情况下,使用简单的32位
int
值是线程安全的,但在32位机器上使用64位
double
不是线程安全的

复制文件的代码在哪里?你是怎么做线程的?请包括你计算完成百分比的代码。由于您的问题与下载的大小有关,很可能是您试图过于频繁地更新进度条(例如,您一次下载10个字节,每次更新进度条;对于100字节的文件,这可以正常工作,但对于15 MB的文件则失败)。@MusiGenesis OP did状态文件低于15 MB,这可能意味着大于100字节,但仍然可能是根本原因。您不使用BackgroundWorker的任何原因?该功能存在于该类中,使您试图做的事情变得微不足道。并不是说没有幕后工作者就无法完成,我只是想弄明白为什么?@AaronMcIver:我用虚构的数字来说明潜在的问题。希望没有人会尝试一次下载10个字节。我完全尝试了这种方法,没有骰子,同样的问题。应用程序锁定较大的文件。我不清楚如何实现BackgroundWorker类,以便与Amazon S3 TransferUtiltyUploadRequest.UploadProgressEvent方法集成。很抱歉,我对所有这些都不清楚…我已经在同一个问题上绞尽脑汁好几天了,似乎找不到解决办法,除了完全取消进度条…我讨厌这样做,讨厌看不到应用程序仍在处理文件。@user1078155-我看到您正在使用
int
作为
PercentDone
。在
UpdateProgressBar
函数中进行检查,看看该值是否实际发生了更改。我不确定您是如何计算
完成百分比的
,但是如果它没有改变,如果您不调用
调用
,它将为您节省一些处理。请看我的更新示例。我把它放进去,除非完成百分比已更改,否则不让进度条尝试更新是有意义的。但它并不能解决这个问题:小文件可以正常工作,大文件会冻结一切。