进度条的BUG?:为什么偶的进度条的Value为100了 而显示出来进度条才走到中间

realljx 2005-03-01 08:57:37
偶的思路是这样的

首先开启定时器 让进度条滚动 然后用BeginInvoke启动一个耗时的操作。
定时器最多可以将滚动条滚到到 倒数第一步
耗时操作的最后才将滚动条滚到最终的位置

有些时候又很正常
有些时候就出现如标题所描述的情况?
当整个过程结束以后 进度条的Value为100了 而显示出来进度条才走到中间

同事们研究了半天 说是进度条的BUG

代码如下

private void button1_Click(object sender, System.EventArgs e)
{
//从这里开始执行
progressBar1.Value = 0;

timer = new System.Timers.Timer();
timer.AutoReset = true;
timer.Interval = 200;
timer.Elapsed +=new System.Timers.ElapsedEventHandler(timer_Elapsed);
timer.Start();

progressBar1.BeginInvoke(
new MethodInvoker(DoSth));
}

private void DoSth()
{
string path = "D:\\a.dot";
Work work = new Work();
work.GetFieldsValues(path);
timer.Stop();

while(progressBar1.Value < progressBar1.Maximum)
progressBar1.PerformStep();
//这里显示已经100了
MessageBox.Show(progressBar1.Value.ToString());
}

private void timer_Elapsed(object sender, System.Timers.ElapsedEventArgs e)
{
if(progressBar1.Value < progressBar1.Maximum -1)
progressBar1.PerformStep();
}
...全文
257 21 打赏 收藏 转发到动态 举报
写回复
用AI写文章
21 条回复
切换为时间正序
请发表友善的回复…
发表回复
realljx 2005-03-01
  • 打赏
  • 举报
回复
给分了,
白掌柜 2005-03-01
  • 打赏
  • 举报
回复
声明一个代理,线程中用Invoke调用UI方法.
nga96 2005-03-01
  • 打赏
  • 举报
回复
UP,可是好像别人可以的
realljx 2005-03-01
  • 打赏
  • 举报
回复
看起来还是线程的问题。
sun926 2005-03-01
  • 打赏
  • 举报
回复
if ( !timer.Enabled )
{
timer.Stop();
this.Invoke( new Callback( ToEnd ) );
}

改成
timer.Stop();
this.Invoke( new Callback( ToEnd ) );
realljx 2005-03-01
  • 打赏
  • 举报
回复
sun926(初学者) :

不过我吧if ( !timer.Enabled )--》 if ( timer.Enabled ) 就可以了 呵呵

谢谢你。。。。。。呵呵呵呵哈呵呵哈合伙
realljx 2005-03-01
  • 打赏
  • 举报
回复
sun926(初学者)

按照你的写法 我试了 结果还是一样 某些时候会停在中间

sun926 2005-03-01
  • 打赏
  • 举报
回复
//个人认为应该这样写:
private void button1_Click(object sender, System.EventArgs e)
{
//从这里开始执行
progressBar1.Value = 0;

timer = new System.Timers.Timer();
timer.Interval = 200;
timer.Elapsed +=new System.Timers.ElapsedEventHandler(timer_Elapsed);
timer.Start();

Thread t = new Thread( new ThreadStart( DoSth ) );
t.Start();
}

System.Timers.Timer timer;

private void DoSth()
{
string path = "D:\\a.dot";
Work work = new Work();
work.GetFieldsValues(path);
if ( !timer.Enabled )
{
timer.Stop();
this.Invoke( new Callback( ToEnd ) );
}
}

delegate void Callback( );
private void ToEnd()
{
while(progressBar1.Value < progressBar1.Maximum)
progressBar1.PerformStep();
}
private void timer_Elapsed(object sender, System.Timers.ElapsedEventArgs e)
{
if(progressBar1.Value < progressBar1.Maximum - 20)
{
progressBar1.PerformStep();
}
else timer.Stop();
}
sun926 2005-03-01
  • 打赏
  • 举报
回复
你用BeginInvoke的方法调用DoSth(),那么DoSth()应该是在UI线程执行的,所以无论怎么样计时器都回阻塞的。
web_gus 2005-03-01
  • 打赏
  • 举报
回复
up
amendajing 2005-03-01
  • 打赏
  • 举报
回复
mark
realljx 2005-03-01
  • 打赏
  • 举报
回复
sun926(初学者):

Stop 是否执行实际上没有影响 因为再下面有一个判断的。
realljx 2005-03-01
  • 打赏
  • 举报
回复
sun926(初学者):

我觉得问题不在timer 因为执行完毕以后 进度条的Value确实已经是100了,(执行完以后可以再检测到的)
所以应该说进度条不是线程安全的

另外 换成System.Windows.Forms.Timer就不行了 因为托管任务的执行导致计时器阻塞不运行。
sun926 2005-03-01
  • 打赏
  • 举报
回复
问题出在同步上,
System.Timers.Timer是从工作线程来激发Elapse事件的,所以该事件并不是线程安全的,因此在Elapse中执行PerformStep()本身就不可靠,
另外Stop()也并不能马上停止Timer,在Stop()之后仍然会激活Elapsed事件,这时就会发生问题的。

所以你的System.Timers.Timer的用法有误,其实按照你的思路,只需要简单的把System.Timers.Timer换成System.Windows.Forms.Timer就可以了。
cdo 2005-03-01
  • 打赏
  • 举报
回复
帮你顶一下。
yiyi0518 2005-03-01
  • 打赏
  • 举报
回复
up~~~

虽然不懂。。。
realljx 2005-03-01
  • 打赏
  • 举报
回复
现在本来就是再两个线程里面运行的啊。

我想知道为什么会是这样.

hehe Thanks .
我不懂电脑 2005-03-01
  • 打赏
  • 举报
回复
每次改变Value的时候ProgressBar.Refresh()一下。
lonelydreamsym 2005-03-01
  • 打赏
  • 举报
回复
up
老汉 2005-03-01
  • 打赏
  • 举报
回复
支持楼上。
加载更多回复(1)

110,545

社区成员

发帖
与我相关
我的任务
社区描述
.NET技术 C#
社区管理员
  • C#
  • Web++
  • by_封爱
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告

让您成为最强悍的C#开发者

试试用AI创作助手写篇文章吧