Reputation: 151
I'm transfering files and would like a progress bar to show the actually progress of each file. This is working fine for files under 15 megs but files greater than that seem to cause my applicaiton to freeze. If I don't call this code for the progress bar, these larger files transfer just fine.
I've tried all sorts of different ways to handle this with delegates but no luck. Rather, they work fine with smaller files but not larger ones.
Some examples that worked...
pbFileProgress.Invoke((MethodInvoker)
delegate
{
pbFileProgress.Value = args.PercentDone;
});
Also, this collection of methods worked for smaller files.
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;
}
But again, everything just freezes if I try larger files.
Upvotes: 4
Views: 9515
Reputation: 49988
You could Invoke based on the UI element. For example:
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;
}
}
Otherwise I would suggest what Aaron McIver did and use the BackgroundWorker class. See the example here for details on updating a progressbar using the BackgroundWorker class
Update
Looks like you are not the only one with this issue. See Amazon s3 Transferutility.Upload hangs in C# here. Kent also points says: If you read in about the S3 forums you'll find many people having similar issues
Upvotes: 0
Reputation: 3383
Despite the lack of context, here's an example that work. The BeginInvoke or Invoke method is called only 100 times max.
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);
}
});
Upvotes: 2
Reputation: 15810
This issue is very common when communicating between background and foreground threads: the background thread is sending the foreground thread too many updates.
The foreground thread handles updating, drawing, and user input, so when too many updates come in, the UI freezes trying to catch up.
Obviously, if the background thread continues to send updates, the foreground can be backed up even after the background task finishes!
There are several solutions to this problem, but my strongest recommendation is to use a Timer
in the foreground thread to poll the background progress and update the UI.
The advantage of using a Timer
:
Timer
can be set to a "reasonable" value, such as 250ms (4 updates per second), so that progress is smooth but doesn't take the whole processorAs always, thread safety is important when communicating the progress between threads. Using a simple 32-bit int
value is thread-safe in this scenario, but using a 64-bit double
is not thread safe on 32-bit machines.
Upvotes: 1