c#进度条调用/委托问题
本文关键字:问题 调用 | 更新日期: 2023-09-27 18:16:53
我正在传输文件,并希望进度条显示每个文件的实际进度。这对于小于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;
}
但是,如果我尝试更大的文件,一切都会死机
尽管缺乏上下文,但这里有一个可行的示例。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);
}
});
这个问题在后台和前台线程之间通信时非常常见:后台线程发送前台线程太多更新。
前台线程处理更新,绘图和用户输入,所以当太多的更新进来时,UI冻结试图赶上。
显然,如果后台线程继续发送更新,前台甚至可以在后台任务完成后备份 !
Timer
来轮询后台进程并更新UI。使用
Timer
的优点:
- 后台线程可以根据需要频繁地报告进程
- 前台线程可以放松,直到需要更新
- 前台线程不会"备份"更新
- 如果前台线程是"休息",那么后台线程得到更多的处理器时间
-
Timer
的频率可以设置为一个"合理"的值,比如250ms(每秒4次更新),这样进程是平稳的,但不占用整个处理器
int
值是线程安全的,但是在32位机器上使用64位double
不是线程安全的。 可以基于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类。有关使用BackgroundWorker类
更新进度条的详细信息,请参阅下面的示例。 看来你不是唯一一个有这个问题的人。参见Amazon s3 Transferutility。上传在c#中挂起。肯特还指出:If you read in about the S3 forums you'll find many people having similar issues