1

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

在此处输入图像描述

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 没有显示进度条值增加的最后 1/3 的动画。目前,代码如下所示:

主窗体:

...
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

4 回答 4

3

这个

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

是邪恶的。不要那样做。而且,此外,您不需要它。我会假设没有它它会工作。

于 2013-07-09T09:05:52.790 回答
3

我认为ProgressBar旨在表示进度有点慢,这样快速或快速的进度(在 25 毫秒内更改 1/50)无法正确(及时)更新。虽然ProgressBar.Value仍然增加并达到最大值以重新启动循环。那时,ProgressBar视觉指示器刚刚达到2/3最大值(与实际相比有所延迟Value),但不知何故,它在0设置值时立即更新视觉指示器并且1/3剩余的视觉指示器没有更新/绘制/渲染。如果你增加Interval你的计时器,比如 to 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传入RectangleRegion

更新

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

yourProgressBar.Style = ProgressBarStyle.Marquee;
yourProgressBar.MarqueeAnimationSpeed = 1;//Change the speed of marquee animation
//You don't need any timer to change its Value at all.
于 2013-07-09T09:59:25.130 回答
0

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

从您的代码中无法查看计时器何时启动和停止!看起来您将更多步骤添加到进度条作为定义的最大值!您每 25 毫秒更改一次进度条的值,该值与您的 SQL 查询加载/读取/等完全没有关系。

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

于 2013-07-09T09:11:02.907 回答
0

您可以尝试更改此行吗:

if (progressBar1.Value < progressBar1.Maximum)

有了这个:

if (progressBar1.Value <= progressBar1.Maximum)
于 2013-07-09T09:04:36.820 回答