C# - 带跑马灯样式的 ProgressBar

C# - ProgressBar with Marquee style

我想在具有跑马灯样式的窗体上添加 ProgressBar,以向用户显示正在进行的事情。在耗时的操作过程中,表单没有得到更新,因此 ProgressBar 也 "freezes".

我查看了几篇关于 BackgroundWorker 的帖子,但在我的例子中,操作没有报告进度,这就是为什么我需要一个 Marquee 栏。

感谢任何帮助或代码片段。

注意:我需要使用 .NET 4.0(用于 XP 支持)所以我不能使用 Task.Run :(

button1_Click(object sender, EventArgs e)
{
    progressBar1.Style = ProgressBarStyle.Marquee;
    progressBar1.MarqueeAnimationSpeed = 50;

    // INSERT TIME CONSUMING OPERATIONS HERE
    // THAT DON'T REPORT PROGRESS
    Thread.Sleep(10000);

    progressBar1.MarqueeAnimationSpeed = 0;
    progressBar1.Style = ProgressBarStyle.Blocks;
    progressBar1.Value = progressBar1.Minimum;

}

您仍然需要 运行 在另一个线程上进行耗时的工作...您 运行 在 UI 线程上进行它,这意味着 UI没有机会做任何 UI 更新(因此你看到了冻结)!

您应该考虑使用 Task<> 而不是 BackgroundWorker

有关 Task<> 的更多信息,请参阅 https://msdn.microsoft.com/en-us/library/hh195051%28v=vs.110%29.aspx


如果您不能使用 Task<> 那么您应该恢复到 BackgroundWorker 并使用 WorkCompleted 事件来停止选取框并将您的程序移至下一个操作。

已解决。但是,我认为这是最不优雅的处理方式。

button1_Click(object sender, EventArgs e)
{
    progressBar1.Style = ProgressBarStyle.Marquee;
    progressBar1.MarqueeAnimationSpeed = 50;


    Task task = Task.Factory.StartNew(() =>
    {
        // INSERT TIME CONSUMING OPERATIONS HERE
        // THAT DON'T REPORT PROGRESS
        Thread.Sleep(10000);
    });

    while (!task.IsCompleted)
    {
         Application.DoEvents();
         Thread.Sleep(1);
    }

    progressBar1.MarqueeAnimationSpeed = 0;
    progressBar1.Style = ProgressBarStyle.Blocks;
    progressBar1.Value = progressBar1.Minimum;

}

I've checked several posts about BackgroundWorker, but in my case the operation doesn't report progress, that's why I need a Marquee bar.

您可以使用 BackgroundWorker,只是不要使用它的 "progress" 部分。这两件事并不相互排斥...

示例:

    private void button1_Click(object sender, EventArgs e)
    {
        button1.Enabled = false;
        progressBar1.Style = ProgressBarStyle.Marquee;
        progressBar1.MarqueeAnimationSpeed = 50;

        BackgroundWorker bw = new BackgroundWorker();
        bw.DoWork += bw_DoWork;
        bw.RunWorkerCompleted += bw_RunWorkerCompleted;
        bw.RunWorkerAsync();
    }

    void bw_DoWork(object sender, DoWorkEventArgs e)
    {
        // INSERT TIME CONSUMING OPERATIONS HERE
        // THAT DON'T REPORT PROGRESS
        Thread.Sleep(10000);
    }

    void bw_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
    {
        progressBar1.MarqueeAnimationSpeed = 0;
        progressBar1.Style = ProgressBarStyle.Blocks;
        progressBar1.Value = progressBar1.Minimum;

        button1.Enabled = true;
        MessageBox.Show("Done!");
    }

首选方案

private void button1_Click(object sender, EventArgs e)
{
    button1.Enabled = false;
    progressBar1.Style = ProgressBarStyle.Marquee;
    progressBar1.MarqueeAnimationSpeed = 50;

    Task.Factory.StartNew(() => {
           // INSERT TIME CONSUMING OPERATIONS HERE
           // THAT DON'T REPORT PROGRESS
           Thread.Sleep(10000);
        }, TaskCreationOptions.LongRunning).
            ContinueWith(t => {
                progressBar1.MarqueeAnimationSpeed = 0;
                progressBar1.Style = ProgressBarStyle.Blocks;
                progressBar1.Value = progressBar1.Minimum;

                button1.Enabled = true;
                MessageBox.Show("Done!");
            }, TaskScheduler.FromCurrentSynchronizationContext());
}

P.S。为了处理可能的操作取消,示例实例化了一个生成取消标记的 CancellationTokenSource 对象。