【问题标题】:Progress bar working but label is not updating进度条工作但标签未更新
【发布时间】:2012-06-18 09:31:16
【问题描述】:

我有一个带有接口的库。

Public Interface Progress
{
    int ProgressValue{get;set;},
    string ProgressText{get;set;},
}

库有一个方法 Create(虚拟代码):

Public Class TestLibrary
{

    Progress _progress;

    Public void Create()
    {
        foreach(var n in TestList)
        {
            // Do Something
            _progress.ProgressValue = GetIndex(n);
            _progress.ProgressText = "Updating..." + n;
        }
    }
}

我有一个引用这个库并调用 Create 方法的项目。它甚至实现了接口进度。

Public Class TestProject : Progress
{
    public int ProgressValue
    {
        get{return progressBar1.Value;}
        set{progressBar1.Value = value;}
    }

    public int ProgressText
    {
        get{return label1.Text;}
        set{label1.Text = value;}
    }
}

现在,当我运行应用程序时,进度条正常运行并正确显示进度,但 label1 的文本根本没有改变。但它确实在 for 循环结束时发生了变化,并显示了循环中的最后一项。谁能帮我解决这个问题?

注意:所有这些代码都是直接编写的,没有经过测试,因为我现在没有我的应用程序。很抱歉有任何语法错误。

【问题讨论】:

  • 出于兴趣完成时它会改变吗?如果是这样,这可能只是线程问题 - 看起来您在 UI 线程中做了太多工作。
  • @JonSkeet:是的,它确实发生了变化。我编辑了问题以反映相同的情况。
  • 这肯定是线程问题 - 确保您的“进度”-代码不在 UI 线程上运行
  • 实际的业务逻辑需要多长时间?如果花费的时间非常少,那么标签更新不会反映在 UI 中(我现在与 backgroundworker 面临类似的事情)。另一方面,如果花费的时间太长,请尝试在每次工作迭代之间休息一下。正如乔恩所说,不要在 UI 线程上做。使用 BackGroundWorker 线程。

标签: c# winforms progress-bar uilabel


【解决方案1】:

听起来您的所有工作都在 UI 线程上完成。不要那样做。

相反,在后台线程中运行循环本身,并使用Control.InvokeControl.BeginInvoke(可能在Progress 实现中)来编组对UI 线程的调用,以更新UI。这将使您的 UI 在处理过程中保持响应(并能够更新标签等)。

【讨论】:

  • 我接受了这个答案,但我对这些事情没有太多了解......经过一定的经验和知识,现在我可以清楚地看到您要指出的内容。谢谢:)
【解决方案2】:

使用了Label instead of ProgressBar。你可以试试这个代码 [using BackGroundWorker] -

using System.ComponentModel;
using System.Windows.Forms;

namespace WindowsFormsApplication1
{
    public partial class Form3 : Form
    {
        private BackgroundWorker _worker;
        BusinessClass _biz = new BusinessClass();
        public Form3()
        {
            InitializeComponent();
            InitWorker();
        }

        private void InitWorker()
        {
            if (_worker != null)
            {
                _worker.Dispose();
            }

            _worker = new BackgroundWorker
            {
                WorkerReportsProgress = true,
                WorkerSupportsCancellation = true
            };
            _worker.DoWork += DoWork;
            _worker.RunWorkerCompleted += RunWorkerCompleted;
            _worker.ProgressChanged += ProgressChanged;
            _worker.RunWorkerAsync();
        }


        void DoWork(object sender, DoWorkEventArgs e)
        {
            int highestPercentageReached = 0;
            if (_worker.CancellationPending)
            {
                e.Cancel = true;
            }
            else
            {
                double i = 0.0d;
                int junk = 0;
                for (i = 0; i <= 199990000; i++)
                {
                    int result = _biz.MyFunction(junk);
                    junk++;

                    // Report progress as a percentage of the total task.
                    var percentComplete = (int)(i / 199990000 * 100);
                    if (percentComplete > highestPercentageReached)
                    {
                        highestPercentageReached = percentComplete;
                        // note I can pass the business class result also and display the same in the LABEL  
                        _worker.ReportProgress(percentComplete, result);
                        _worker.CancelAsync();
                    }
                }

            }
        }

        void RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
        {
            if (e.Cancelled)
            {
                // Display some message to the user that task has been
                // cancelled
            }
            else if (e.Error != null)
            {
                // Do something with the error
            }
        }

        void ProgressChanged(object sender, ProgressChangedEventArgs e)
        {
            label1.Text =  string.Format("Result {0}: Percent {1}",e.UserState, e.ProgressPercentage);
        }
    }

    public class BusinessClass
    {
        public int MyFunction(int input)
        {
            return input+10;
        }
    }
}

前几天发过同样的here

【讨论】:

  • cool... 这是在 Winforms 世界中使用 backgroundworker 完成此类任务的合理/标准方式。
【解决方案3】:

您发布的代码使用一个线程。这意味着每个操作都在前一个操作完成后按顺序执行。 由于您可以立即更新 GUI 元素,我想代码将从主线程(又名“GUI 线程”)运行。阻塞 GUI 线程会导致 GUI(“图形用户界面”)在有空闲时间之前不会更新。

使用以下示例在每次迭代时刷新您的标签,以便更新您的 UI。

label1.Text = i.ToString();
label1.Refresh();

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2020-11-05
    • 2017-10-07
    • 1970-01-01
    • 2015-04-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-07-20
    相关资源
    最近更新 更多