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

本文关键字:标签 更新 ProgressChanged | 更新日期: 2023-09-27 18:01:47

我有一个后台工作人员长时间运行的任务。该任务遍历一个文件列表,我想要更新我们正在使用的文件的用户。我有一个工具条,它的标签名为panel1.text。进度条正在工作,但是我的ProgressChanged方法中的标签没有改变,即它应该说处理File1,然后更改为处理File2,但它保持默认的处理。

    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
        }
    }   

我将感激任何帮助。

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

您正在使用同一线程,该线程被另一个进程阻塞。您需要使用Task来创建一个新线程,可能还需要使用Dispatcher。如果控件在另一个线程上,则调用beginiinvoke。确保任何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)});

然后在标签类内部或标签所在的地方:

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}");`

就在你进入Task之前——它会给你主线程ID然后在Task中再次调用它…这将给你第二个线程ID。
然后在Dispatcher调用之前:

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

如果你有访问权限,它将显示True,如果没有,它将显示False…在你的例子中,它将显示false,因为它属于另一个线程,但是你可以使用Dispatcher在另一个线程中处理该线程的工作…

另外,我建议你不要使用后台工作器,而是使用任务…这就解释了为什么……基本上,任务可以完成后台工作人员所做的一切,甚至更多,问题更少,更容易使用…

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

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

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

根据您的评论,将这些后期处理移动到BackgroundWorker。RunWorkerCompleted事件