【问题标题】:How to prevent program from not responding while a loading bar is present如何在加载栏存在时防止程序无响应
【发布时间】:2019-10-19 10:09:39
【问题描述】:

我正在创建一个程序,它可以在启动时从文件中读取大量数据。

我尝试了一个进度条来显示加载进度,希望它能停止无响应,但它在中途冻结并更新屏幕上的标签以解决问题。

//This will be 'private void Form1_Shown(object sender, EventArgs e)'
private void loadingBarToolStripMenuItem_Click(object sender, EventArgs e)
{
    progressBar1.Show();
    for (int i = 0; i < 100; i++)
    {
        progressBar1.Value = i;
        System.Threading.Thread.Sleep(50);
        //StartRespondingAgain();
    }
    progressBar1.Hide();
}

【问题讨论】:

  • 如果您的工作量很大,请将其转移给后台工作人员!从那里您可以更新进度条。周围有很多例子...... - 无论睡眠应该做什么,你都不想要它! ((也不是任何 Application.DoEvents !!))
  • 如果不想使用多线程,可以在循环中添加progressBar1.Refresh()Application.DoEvents()Sleep()前面,可以去掉。
  • 实际上这似乎只是工作,因为没有实际负载。
  • @TaW 我在调试程序时发生了同样的事情,但是在从文件资源管理器运行程序时遇到了问题。我认为从 Visual Studio 调试时,无响应功能被禁用。

标签: c# visual-studio


【解决方案1】:

这个问题不是加载栏,而是你在 GUI 线程上运行了长时间的操作。

应该调用事件,完成它们的工作并尽快返回。只能同时运行一段代码,并且当此事件运行时,不能执行其他事件 - 甚至不能执行更改的绘制。

您需要添加某种形式的多任务处理。此操作不会受益于大量线程/任务(例如每个文件一个),但至少可以将长时间运行的循环移至单独的任务中。 BackgroundWorkers、Threads 和 Async/Await 只是 3 种方法。我个人认为 BackgroundWorker 很好——但有点过时了——学习多任务处理,尤其是多线程处理的“训练轮”。我什至得到了一些示例代码:

#region Primenumbers
private void btnPrimStart_Click(object sender, EventArgs e)
{
    if (!bgwPrim.IsBusy)
    {
        //Prepare ProgressBar and Textbox
        int temp = (int)nudPrim.Value;
        pgbPrim.Maximum = temp;
        tbPrim.Text = "";

        //Start processing
        bgwPrim.RunWorkerAsync(temp);
    }
}

private void btnPrimCancel_Click(object sender, EventArgs e)
{
    if (bgwPrim.IsBusy)
    {
        bgwPrim.CancelAsync();
    }
}

private void bgwPrim_DoWork(object sender, DoWorkEventArgs e)
{
    int highestToCheck = (int)e.Argument;
    //Get a reference to the BackgroundWorker running this code
    //for Progress Updates and Cancelation checking
    BackgroundWorker thisWorker = (BackgroundWorker)sender;

    //Create the list that stores the results and is returned by DoWork
    List<int> Primes = new List<int>();


    //Check all uneven numbers between 1 and whatever the user choose as upper limit
    for(int PrimeCandidate=1; PrimeCandidate < highestToCheck; PrimeCandidate+=2)
    {
        //Report progress
        thisWorker.ReportProgress(PrimeCandidate);
        bool isNoPrime = false;

        //Check if the Cancelation was requested during the last loop
        if (thisWorker.CancellationPending)
        {
            //Tell the Backgroundworker you are canceling and exit the for-loop
            e.Cancel = true;
            break;
        }

        //Determin if this is a Prime Number
        for (int j = 3; j < PrimeCandidate && !isNoPrime; j += 2)
        {
            if (PrimeCandidate % j == 0)
                isNoPrime = true;
        }

        if (!isNoPrime)
            Primes.Add(PrimeCandidate);
    }

    //Tell the progress bar you are finished
    thisWorker.ReportProgress(highestToCheck);

    //Save Return Value
    e.Result = Primes.ToArray();
}

private void bgwPrim_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
    pgbPrim.Value = e.ProgressPercentage;
}

private void bgwPrim_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
    pgbPrim.Value = pgbPrim.Maximum;
    this.Refresh();

    if (!e.Cancelled && e.Error == null)
    {
        //Show the Result
        int[] Primes = (int[])e.Result;

        StringBuilder sbOutput = new StringBuilder();

        foreach (int Prim in Primes)
        {
            sbOutput.Append(Prim.ToString() + Environment.NewLine);
        }

        tbPrim.Text = sbOutput.ToString();
    }
    else 
    {
        tbPrim.Text = "Operation canceled by user or Exception";
    }
}
#endregion

但那是你可以挑选毒药的地方。

【讨论】:

  • 感谢您的快速回答,但我认为在这种情况下多线程不是最佳选择,因为我不希望用户在读取数据时更改任何数据。在保存数据时尤其如此。
  • @DoshorteDovencio 然后不要给用户选项在数据全部读取之前更改数据,在完成之前不显示任何内容或启用编辑。您将需要执行一些形式的多任务处理,如果是DoEvents()。这个问题只有一个解决方案,但是你有很多方法可以做到。
  • 是否还有一种锁定应用程序的方法,以便用户无法更改 System.IO.lockbuttons() 之类的任何内容?
  • 最简单的方法是在 UI 上不显示任何内容,直到所有数据都准备好。并在您开始检索一组新数据时对其进行清理。否则,翻转容器上的启用状态是一种快速但肮脏的方式。但这也会禁用滚动条之类的东西,所以这可能不是正确的想法。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2012-01-19
  • 2016-09-20
  • 2021-10-03
  • 1970-01-01
  • 2021-10-24
  • 2018-08-18
  • 2020-12-31
相关资源
最近更新 更多