多线程时,Progressbar未显示正确的值

时间:2013-07-09 09:02:21

标签: c# .net multithreading winforms progress

在我的MainForm上,我启动了一个执行SQL相关工作的线程。与此同时,我希望使用进度条显示一个新表单,以确认该程序仍在响应。我遇到的问题是Progressbar没有显示正确的值。我希望Progressbar一遍又一遍地从最小值变为最大值,以确保用户程序不会卡住。但是,进度条没有按照我想要的方式显示,因为当它达到最大值的2/3时它会重置。因此,进度条显示从最小值到最大值的2/3的值。下面是Progressbar重置为Value = 0;

的图片

enter image description here

MainForm包含以下代码:

List<Table> ContentList = new List<Table>();
using (ConnectingForm CF = new ConnectingForm())
{
    CF.StartPosition = FormStartPosition.Manual;
    CF.Show(this);
    Thread thread = new Thread(() => { ContentList = DBL.LoadSQLData(); });
    thread.Start();
    DBL.SQLdone = false;
    while (!DBL.SQLdone);
    this.Focus();
    CF.Hide();
}

ConnectingForm具有以下代码:

public ConnectingForm()
{
    InitializeComponent();
    progressBar1.Value = 0;
    progressBar1.Minimum = 0;
    progressBar1.Maximum = 50;
    progressBar1.Step = 1;
    timer1.Interval = 25;
    timer1.Enabled = true;
}

private void timer1_Tick(object sender, EventArgs e)
{
    if (progressBar1.Value < progressBar1.Maximum)
        progressBar1.PerformStep();
    else
        progressBar1.Value = 0;
}

我还尝试在while循环中设置Progressbar的值。但问题仍然存在:UI不会显示Progressbar Value增加的最后1/3的动画。目前代码如下:

的MainForm:

...
Thread thread = new Thread(() => { ContentList = DBL.LoadSQLData(); });
thread.Start();
DBL.SQLdone = false;
while (!DBL.SQLdone)
{
    if (CF.Value == CF.Maximum)
         CF.Value = 0;
    else
         CF.Value += 1;
    Thread.Sleep(100);
}
...

虽然ConnectingForm看起来像这样:

public ConnectingForm()
{
    InitializeComponent();
    progressBar1.Value = 0;
    progressBar1.Minimum = 0;
    progressBar1.Maximum = 20;
    progressBar1.Step = 1;
}
public int Value
{
    set { progressBar1.Value = value; }
    get { return progressBar1.Value; }
}
public int Maximum
{
    get { return progressBar1.Maximum; }
}

仍然会给出相同的结果。进度条仅显示值0到2/3,然后重置。

我希望有人可以帮我弄清楚我做错了什么。 提前谢谢!

4 个答案:

答案 0 :(得分:3)

Application.DoEvents();
Thread.Sleep(10);

是邪恶的。不要那样做。此外,你不需要它。我认为没有它我会工作。

答案 1 :(得分:3)

我认为ProgressBar旨在表明进度稍慢,如此快速或快速的进度(在25毫秒内变化1/50)无法正确更新(及时)。虽然ProgressBar.Value仍然增加并达到最大值以重新启动循环。那时,ProgressBar视觉指示符刚好达到最大值2/3(与实际Value相比延迟),但不知何故,当值{{{}时,它会更新视觉指示符1}}已设置且0剩余的可视指示符未更新/绘制/呈现。如果您将计时器的1/3增加到Interval,则可以看到它在从头开始重新启动之前贯穿所有栏。我认为这是设计上的,不能改变它的工作方式。你有一些选择(我能想到):

1000

也许您必须测试它是否贯穿进度条的所有长度,并相应地更正1. Try creating your own progress indicator and make it update the visual indicator the way you want, however I think it may cause some small issue related to performance. 2. Try cutting off the `non-updated visual part of your ProgressBar` using `Region` property like this: //First, try drawing the length of your ProgressBar more because we have to cut off the remaining non-updated visual part of it. yourProgressBar.Region = new Region(new Rectangle(Point.Empty, new Size(2*yourProgressBar.Width/3, yourProgressBar.Height)));//placing this in your Form constructor is OK. 中传递的Width的{​​{1}}。

更新

实际上Rectangle支持工作进度指示器(不关心百分比),我认为您可能希望在不创建任何其他控件或使用第三方控件的情况下使用它。所有你需要的是:

Region

答案 2 :(得分:0)

你能尝试改变这一行:

if (progressBar1.Value < progressBar1.Maximum)

这一个:

if (progressBar1.Value <= progressBar1.Maximum)

答案 3 :(得分:0)

首先要做的事情:通常你不是在计时器中更改进度条的值,而是在进程的每个工作单元(步骤)中更改,因此在您的情况下,进度条应在中更改环

从您的代码中无法看到定时器启动和停止的时间!您似乎向进度条添加了更多步骤作为定义的最大值!您每25毫秒更改一次进度条的值,并且该值与您的SQL查询加载/读取/等没有任何关联。

因此,您需要更改程序的流程和逻辑,以便设置正确的值。如果要从线程更新进度条,还需要了解对UI元素的跨线程访问。