【问题标题】:Is it Possible to Make a Simple C# Marquee Progress Bar without a Background Worker?是否可以在没有后台工作人员的情况下制作简单的 C# 字幕进度条?
【发布时间】:2016-08-11 05:38:33
【问题描述】:

我有一个非常简单的表单,上面有一个进度条和一个删除按钮。当用户单击“删除”时,存储过程会运行大约五分钟。

我想运行一个简单的选取框进度条,但它从未出现。我阅读了有关此的所有其他问题,但它们都需要背景工作人员。

是否可以在没有后台工作人员的情况下制作字幕进度条?

    public partial class ProgressBarSample
{
    public ProgressBarSample

        {
            progressBar1.Style = ProgressBarStyle.Marquee;
            progressBar1.Visible = false;
        }


    private void btnDelete_Click(object sender, EventArgs e)
        {
            progressBar1.Visible = true;
            // run stored procedure that takes around 5 minutes
            Task.Delay(10000);
            progressBar1.Visible = false;
        }
}

【问题讨论】:

    标签: c# .net progress-bar


    【解决方案1】:

    你的代码

    progressBar1.Visible = true;
    // run stored procedure that takes around 5 minutes
    Task.Delay(10000);
    progressBar1.Visible = false;
    

    阻止您的应用程序处理 Windows 消息,直到延迟完成,因为您阻塞了负责处理这些消息的线程。 Windows 依赖于及时处理这些消息。

    结果是您的用户界面将显示为对用户没有响应。

    有许多机制允许您在第二个线程上进行处理。 BackgroundWorker 是 WinForms 首次出现时常用的一种,并且仍然是一个可靠的选择。您可以使用在另一个线程上执行长时间运行工作的任何技术,但您必须在另一个线程上执行此操作。

    您可以使用异步模式来简化其他线程的编码

    private async void btnDelete_Click(object sender, EventArgs e)
    {
        progressBar1.Visible = true;
        await Task.Run(() =>
        {
            // run stored procedure that takes around 5 minutes
            Task.Delay(10000);
        });
        progressBar1.Visible = false;
    }
    

    【讨论】:

    • 您评论的代码并没有按照您说的那样做,因为Task.Delay() 方法不会阻塞。现在,如果 OP 发布了一个不好的问题,他们提供的代码实际上并不能重现他们遇到的特定问题,实际上他们有一些东西 does 代替 where他们目前显示Task.Delay(),那么您的建议会更合适。但是你回答的问题与被问到的不同。
    【解决方案2】:

    如果没有一个好的Minimal, Complete, and Verifiable code example 可以可靠地重现您的问题,就不可能确定问题出在哪里。但是,您发布的代码将不起作用。您的btnDelete_Click() 方法将Visible 属性设置为true,但随后立即将其设置回false,因为Task.Delay() 方法实际上并没有阻塞。

    你想要的大概是这样的:

    private async void btnDelete_Click(object sender, EventArgs e)
    {
        progressBar1.Visible = true;
        // run stored procedure that takes around 5 minutes
        await Task.Delay(10000);
        progressBar1.Visible = false;
    }
    

    【讨论】:

    • 代码示例似乎足以理解问题。一个完整的(可编译的)WinForms 示例有很多会影响核心问题的包袱。他在他的真实代码中插入了 Task.Delay 作为对存储过程的调用的代理,因此 Task.Delay 并不是他所追求的。
    • @EricJ.:插入一个非阻塞调用作为阻塞调用的代理虽然看似合理,但却是错误,并且会阻止任何人真正了解代码的作用。如果他们想要一个真正解决他们问题的答案,OP 需要提供一个好的minimal reproducible example
    【解决方案3】:

    BackgroundWorker 是进行此类后台工作的普遍接受的方法,因此得名;但是对于原始的“显示 X 时间段”,您可以使用 Timer 来检查自上次单击(在这种情况下)删除以来经过的时间量,以查看它是否应该隐藏控件(并禁用自身,没有用无事可做时打勾。)

    类似:

    public partial class ProgressBarSample
    {
        TimeSpan pbShowDuration = [blah blah];
        DateTime pbShowFrom = DateTime.MinDate;
    
        public ProgressBarSample
        {
            progressBar1.Style = ProgressBarStyle.Marquee;
            progressBar1.Visible = false;
        }
    
        private void btnDelete_Click(object sender, EventArgs e)
        {
            progressBar1.Visible = true;
            pbShowFrom = DateTime.Now;
            timer1.Enabled = true;
            // run stored procedure that takes around 5 minutes
        }
    
        private void timer1_Tick(object sender, EventArgs e)
        {
            if ((DateTime.Now - pbShowFrom) > pbShowDuration)
            {
                timer1.Enabled = false;
                progressBar1.Visible = false;           
            }
        }
    }
    

    但是你打算如何更新进度条呢?

    【讨论】:

    • 存储过程的运行时间不是很可预测。在数据较少的 QA 服务器上,它可能会在 2 分钟内完成,如果服务器负载过重或服务器在未来某个时间点有更多数据,它可能会在 10 分钟内完成。为[blah blah] 插入合适的时间几乎是不可能的。
    • @EricJ。只看问题中包含的内容,以及为什么我在示例前面加上“原始'显示 X 时间段'”的描述。显然,理想的解决方案是 backgroundworker 或其他形式的线程;大多数需要进度条的任务都不是高度可预测的(不仅仅是存储过程),如果其他进程对存储介质/带宽造成足够的负担,即使加载文件也会有很大差异。
    • @Uueerdo - 选框只是转了一圈,这正是我想要的。
    【解决方案4】:

    借助 C# 中的新任务、同步、等待功能,您有很多选择。如果除了让用户知道操作已完成之外您不需要做任何事情,您可以启动进度条,然后启动运行您的 proc 的任务,完成后停止进度条。我个人会放一些进度条以外的东西。对我来说,进度条意味着你有有限的时间等待。如果您的 SP 可以随时间变化,我会使用某种繁忙的显示图标或类似的东西。

    在这种情况下,我个人会使用 Task.ContinueWith。

    这篇 MSDN 文章展示了处理它的好方法。

    https://msdn.microsoft.com/en-us/library/dd270696(v=vs.110).aspx

    【讨论】:

      【解决方案5】:

      Background worker 是一种旧方法,已被 Tasks 取代。任务有更多的功能,可以做后台工作者不能做的事情,并且使用起来更简单。

      【讨论】:

        猜你喜欢
        • 2012-06-11
        • 1970-01-01
        • 2011-10-07
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多