带标签的进度条 - 无法在ProgressChanged中更新标签

时间:2016-08-09 18:17:39

标签: c#

我有一个背景工作者,他的任务很长。该任务遍历文件列表,我想更新用户所在的文件。我有一个工具条,其标签名为panel1.text。进度条正在运行,但标签在我的ProgressChanged方法中没有变化,即它应该说Processing File1然后更改为Processing File2,但它保持默认的Processing。

    private void btnProcess_Click(object sender, EventArgs e)
    {
        toolStripProgressBar1.Visible = true;
        toolStripProgressBar1.Maximum = 1000000000;
        panel1.Text = "Processing ";    // this appears properly
        BackgroundWorker worker = new BackgroundWorker();
        worker.DoWork += new DoWorkEventHandler(processFiles);
        worker.ProgressChanged += ProgressChanged;
        worker.RunWorkerAsync();
        while (worker.IsBusy)
        {
            // the reason for this is because nothing can happen until the processing is done
            toolStripProgressBar1.Increment(1);
        }
        // more processing
    }

    private void ProgressChanged(object sender, ProgressChangedEventArgs e)
    {
        panel1.Text = "Processing "+ e.UserState.ToString();  <<<----  This is Not Updating panel1.Text but it evaluates properly
    }

     private void processFiles(object sender, EventArgs e)
    {
        int retVal = 0;
        foreach (string fileName in listBox1.Items)
        {
            ProgressChangedEventArgs ea = new ProgressChangedEventArgs(1,fileName);
            ProgressChanged(this, ea);

            // do more processing

        }
    }   

我将不胜感激任何帮助。

2 个答案:

答案 0 :(得分:1)

正如Ivan已经评论过的那样,删除while循环while (worker.IsBusy),因为它阻止了UI线程进一步处理。同样,您应该启用WorkerReportsProgresstrue

    worker.WorkerReportsProgress = true;
    worker.ProgressChanged += ProgressChanged;
    while (!worker.IsBusy)
    {
       worker.RunWorkerAsync();
    }

根据您的评论,将后续处理移至BackgroundWorker.RunWorkerCompleted Event

答案 1 :(得分:1)

您正在使用同一个线程,该线程被另一个进程阻止。如果控件在另一个线程上,则需要使用Task创建新线程并可能使用Dispatcher.BeginIvoke。确保发生的任何Button Click等都标记有Async关键字,以使其成为异步。

示例:

Await Task mytask = Task.Run(() => 
                             for(var i = 0; i < 1000; i++)
                             {
                                Label.Dispatcher.BeginInvoke( () =>
                                                                 UpdateMe(int i, LabelClass/Component class/component)});

然后在Label Class内部或标签所在的位置:

Public void UpdateMe(int i, LabelClass class)
{
  class.label.content = Cint((i/Total)*100);
  Thread.Sleep(500);
}

还有其他方法可以做到这一点,例如将值绑定到UI,但这样可以更好地理解为什么它不起作用以及如何与其他线程一起工作。

如果你想真正获得视觉理解的话:

 `Console.WriteLine($"Current Thread ID: System.Threading.Thread.CurrentThread.ManagedThreadId}");`

在你进入任务之前 - 它会给你主线程ID 然后在Task中再次调用它...这将为您提供辅助线程ID 然后就在Dispatcher调用之前:

Console.WriteLine($"Do I have access to the label on this thread? {Label.Dispatcher.CheckAccess()}";

如果你有访问权限,它将显示True,否则它将显示False ...在你的情况下,它将显示false,因为它由另一个线程拥有,但你可以使用Dispatcher能够对它进行操作在另一个线程中的线程...

另外,我建议你不要使用后台工作者而不是使用任务...这解释了为什么深入...基本上任务做了一切后台工作人员做的更多,问题更少,更容易使用... < / p>

http://blog.stephencleary.com/2013/09/taskrun-vs-backgroundworker-conclusion.html