c# - 多线程时进度条不显示正确的值

标签 c# .net multithreading winforms progress

在我的 MainForm 上,我启动了一个线程来执行一些与 SQL 相关的工作。与此同时,我想要一个新的表单来显示一个进度条,以确认程序仍在响应。我遇到的问题是 Progressbar 没有显示正确的值。我希望 Progressbar 一遍又一遍地从 Minimum 变为 Maximum,只是为了确保用户程序没有卡住。然而,进度条并没有按照我想要的方式显示,因为它会在达到最大值的 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 的动画。目前代码如下所示:

主窗体:

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

仍然给出相同的结果。 Progressbar 只显示 Value 0 到 2/3,然后它被重置。

我希望有人能帮我找出我做错了什么。 提前致谢!

最佳答案

我认为 ProgressBar 旨在指示有点慢的进度,如此快或快速的进度(在 25 毫秒内更改 1/50)无法正确(及时)更新。而 ProgressBar.Value 仍然增加并达到最大值以重新启动循环。那时,ProgressBar 视觉指示器刚好达到最大值的 2/3(与实际 Value 相比有所延迟),但不知何故它会在设置值 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.

也许你必须测试它是否贯穿你的进度条的所有长度并更正 Region 中传递的 RectangleWidth相应地。

更新

事实上 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.

关于c# - 多线程时进度条不显示正确的值,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/17544104/

相关文章:

c# - 使图表图例代表两种颜色

c# - Entity Framework : table without primary key

c# - 内存缓存 - SQLite 与 System.Data.DataTable

C# (mono) 没有利用所有内核

java - 多线程 Zip 文件读取器

c# - 使用 async/await 时使用未分配的局部变量

c# - 同时多次调用api的最佳方法是什么?

java - synchronized 方法不将 int 作为其有效参数?

c# - 如何保存从 Random.Next 方法 C# 生成的值

c# - 按可以为 null 的父对象对 IList<Person> 进行排序