2011-12-06 102 views
4

我正在傳輸文件,並希望進度條顯示每個文件的實際進度。這對於15兆以下的文件工作正常,但文件大於此似乎導致我的應用程序凍結。如果我不爲進度條調用此代碼,這些較大的文件傳輸很好。C#進度條調用/委託問題

我試過各種不同的方式來處理與代表但沒有運氣。相反,他們可以用更小的文件但沒有更大的文件正常工作。

一些例子,工作...

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; 
} 

但是,如果我嘗試更大的文件,一切都會凍結。

+1

複製文件的代碼在哪裏?你怎麼做線程? –

+3

請在計算完成百分比的位置包含代碼。由於您的問題與下載大小有關,因此很可能您嘗試頻繁更新進度欄(例如,您一次下載10個字節並每次更新進度欄;這對100字節文件,但15 MB文件失敗)。 – MusiGenesis

+0

@MusiGenesis OP做了15MB以下的狀態文件,這可能意味着大於100字節,但仍可能是根本原因。 –

回答

0

您可以基於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; 
    } 
} 

否則我會建議什麼亞倫·麥基弗沒有和使用BackgroundWorker類。 查看更新使用BackgroundWorker類

更新 一個進度的詳細信息,例如here看起來,你是不是唯一一個有這個問題。請參閱Amazon s3 Transferutility.Upload hangs in C#。肯特還指出:If you read in about the S3 forums you'll find many people having similar issues

+0

我試過這個方法,沒有骰子,同樣的問題。應用程序鎖定較大的文件。 我不清楚如何實現BackgroundWorker類,以便與Amazon S3 TransferUtiltyUploadRequest.UploadProgressEvent方法集成。 我對所有這些都不明確表示歉意......我一直在這個問題上抨擊我的頭幾天,似乎無法找到解決辦法,只是完全取消了進度條。 。我討厭這樣做,討厭沒有看到該應用程序仍在處理文件。 – user1078155

+0

@ user1078155 - 我看到你正在使用'int'作爲'PercentDone'。如何在'UpdateProgressBar'函數中檢查一下,看看這個值是否真的發生了變化。我不確定你如何計算'PercentDone',但如果它沒有改變,如果你沒有調用'Invoke',它會爲你節省一些處理。看我更新的例子。 – SwDevMan81

+0

我把它放進去,有意義的是沒有進度條嘗試更新,除非完成百分比已經改變。但它不能解決問題:小文件正常工作,大文件凍結了一切。 – user1078155

2

儘管缺乏上下文,這是一個工作的例子。 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); 
     } 
    }); 
1

這個問題的背景和前景線程間通信時是很常見的:後臺線程發送前臺線程太多更新。

前臺線程處理更新,繪圖和用戶輸入,所以當更新過多時,UI將凍結,試圖追趕。
顯然,如果後臺線程繼續發送更新,前景可以在後臺任務完成後備份,即使是

有幾種解決這個問題,但我最大的建議是在前臺線程使用Timer調查背景的進步和更新UI。
使用的優勢Timer

  • 後臺線程可以爲經常需要報告的進展
  • 前臺線程可以放鬆,直到需要更新
  • 前臺線程不會「回來up「更新
  • 如果前景線程」休息「,則後臺線程獲得更多處理器時間
  • Timer的頻率可以設置爲」合理「值,例如250毫秒(每秒4次更新),這樣進度很順利,但不會佔用整個處理器

一如既往,線程安全性在傳遞線程之間的進程時非常重要。在這種情況下,使用簡單的32位int值是線程安全的,但在32位機器上使用64位double不是線程安全的。