问题描述
在实现一个子线程进行网络文件下载,需要记录下载文件队列完成进度,以及每个文件下载进度。子线程中下载每一个文件是一个阻塞代码,也就是代码是在一个线程中往下执行,下载过程中需要向UI更新当前文件下载进度,使用进度条A表示,下载完毕后,要更新下载多个文件队列的进度,使用进度条B表示。
假设当前有3个文件需要下载,第一个文件下载完毕,进度条B就需要更新到1/3位置,进度条的更新代码是依靠Window.Dispatcher来执行的。
this.Dispatcher.BeginInvoke(new Action(() => {
//ui更新代码写在这里
}));
整体代码结构如下:
new Thread(()=>{
for(int i=0;i<list.Count;i++)//list为下载队列
{
//下载....
// ....
//下载完毕
this.Dispatcher.BeginInvoke(new Action(() => {
//ui更新代码写在这里
progressBar.value=i*1.0/list.Count*100;//问题:i总是不从0开始,而是从1开始,滞后一个
}));
}
list.clear();
}).start();
分析
经过变量i的跟踪:
new Thread(()=>{
for(int i=0;i<list.Count;i++)//list为下载队列
{
//下载....
// ....
//下载完毕
Console.WriteLine("i={0},list.Count={1}", i, list.Count);
this.Dispatcher.BeginInvoke(new Action(() => {
//ui更新代码写在这里
Console.WriteLine("Dispatcher:i={0},list.Count={1}",i, list.Count);
progressBar.value=i*1.0/list.Count*100;//问题:i总是不从0开始,而是从1开始,滞后一个
}));
}
list.clear();
}).start();
发现日志输出:
i=0,list.Count=3
Dispatcher:i=1,list.Count=3
i=1,list.Count=3
Dispatcher:i=2,list.Count=3
i=2,list.Count=3
Dispatcher:i=1,list.Count=0
总是滞后于子线程执行。
解决
new Thread(()=>{
for(int i=0;i<list.Count;i++)//list为下载队列
{
//下载....
// ....
//下载完毕,更新进度
int j=i;//复制一份i的值到j中,即使i变更了,也暂时不影响j
int count=list.Count;
//因为Dispatcher调度后的代码执行,不马上立即执行,会滞后,当执行调度后的代码时,i和list.Count的值已经发生了变化。
Console.WriteLine("j={0},count={1}", j, count);
this.Dispatcher.BeginInvoke(new Action(() => {
//ui更新代码写在这里
Console.WriteLine("Dispatcher:j={0},count={1}",j, count);
progressBar.value=j*1.0/count*100;//问题:滞后执行,值变量赋值后得以解决。
}));
}
list.Clear();
}).start();
日志输出:
j=0,count=3
Dispatcher:j=0,count=3
j=1,count=3
Dispatcher:j=1,count=3
j=2,count=3
Dispatcher:j=2,count=3
网友评论