C#在线程期间从外部方法更新进度表

时间:2018-07-13 14:26:53

标签: c# multithreading

已经准备好进行投票表决,但是与这个背景工作人员之间我真的无法完全了解线程的来龙去脉,但是我已经设法为我想要的内容搭建了一个结构:

public class cls1
    {

        private FormProgress myProgForm = new FormProgress();
        public BackgroundWorker worker = new BackgroundWorker();   // new instance of bkgworker

        public void prepare_a_job()
        {
            worker.WorkerReportsProgress = true;                // Allows the worker to report progress
            worker.ProgressChanged += worker_ProgressChanged;   // Adding handler to update progress
            worker.DoWork += job1;                              // Adding handler for the ACTUAL JOB METHOD

            myProgForm.Show();                                  // Show the prog update form
            worker.RunWorkerAsync();                            // Start the job, already! Wo lo loo
        }

        void job1(object sender, EventArgs e)                   // Do 0 to 100
        {
            for (int i = 0; i <= 100; i++)
            {
                (sender as BackgroundWorker).ReportProgress(i); // ReportProgress uses percentages
                Thread.Sleep(50);
            }
            // THIS IS WHERE I'D INSERT ANOTHER METHOD
        }

        void worker_ProgressChanged(object sender, ProgressChangedEventArgs e)
        {
            if(e.ProgressPercentage == 100)  // If the % gets to 100
            {
                myProgForm.UPDATEME("", true);   // then pass true to close progressForm
            }
            else
            {
                myProgForm.UPDATEME("Counting\n" + e.ProgressPercentage);  // else just update 
            }

        }
    }

在我的FormProgress上我有以下方法:

public void UPDATEME(string MSG, bool finish = false)
    {
        this.label1.Text = MSG;
        this.Refresh();
        if (finish) { this.Close(); }
    }

凌乱吧?但这确实有效(而且我24个小时一直在尝试查找/学习这些东西,这是我什至遥不可及的第一件事。

我遇到的问题是,在job1例程中,我想从其他任何要调用的方法中调用UPDATEME()方法,例如实际上,这不只是浪费时间的循环,而是一系列条件,以各种顺序调用大量其他方法。

我尝试将第二种方法绑定到job1中,并在该第二种方法调用UPDATEME中进行捆绑,但这不是线程安全的跨线程更新...

我认为这可能与调用有关,但是随后我还阅读了有关MSDN BackgroundWorker的另一种信息,该方式允许线程安全而无需调用,然后我的脑袋爆炸了,我的大脑掉了下来。

如何在代码中的任何其他方法中始终引用我的ProgressForm.UPDATEME("new progress message")方法?

编辑:

例如,我将在job1调用中插入对此第二个方法的调用

void myOtherMethod()
    {
        (worker).ReportProgress(0);
        myProgForm.UPDATEME("Doing part 1");
        Thread.Sleep(1000);
        myProgForm.UPDATEME("Doing part 2");
        Thread.Sleep(1000);
        myProgForm.UPDATEME("Doing part 3");
        Thread.Sleep(1000);
    }

1 个答案:

答案 0 :(得分:1)

  

如何始终引用我的ProgressForm.UPDATEME(“新进度   message”)方法在我代码中的其他任何方法中?

赞:

public void UPDATEME(string MSG, bool finish = false)
{
    if (this.InvokeRequired)
    {
        this.Invoke(new MethodInvoker(() => this.UPDATEME(MSG, finish)));
    }
    else
    {
        this.label1.Text = MSG;
        if (finish) { this.Close(); }
    }
}
  

我不太了解如何从内部调用该方法   解决方法在第一个级别之外被调用的事实   线程...

一开始它令人困惑,因为这是递归调用。 “肉”是Invoke()在创建控件的同一线程(在这种情况下为表单本身)上运行其内部的内容。当我们第二次进入该方法时(由于递归),该检查返回false,并在UI线程上安全地运行else块。

您实际上可以通过始终调用Invoke()来摆脱检查(和递归),就像这样:

public void UPDATEME(string MSG, bool finish = false)
{
    this.Invoke(new Action(() =>
    {
        this.label1.Text = MSG;
        if (finish) { this.Close(); }
    }));
}

这是一个替代版本,它仍在检查是否需要Invoke(),但不使用递归(减少混乱,但是我们现在引入了重复的代码):

public void UPDATEME(string MSG, bool finish = false)
{
    if (this.InvokeRequired)
    {
        this.Invoke(new Action(() =>
        {
            this.label1.Text = MSG;
            if (finish) { this.Close(); }
        }));
    }
    else
    {
        this.label1.Text = MSG;
        if (finish) { this.Close(); }
    }
}

对于那些“注重细节”的人,这是一种方法/变体(我使用MethodInvoker而不是Action)显示了一种删除上面重复代码的方法:

public void UPDATEME(string MSG, bool finish = false)
{
    if (this.InvokeRequired)
    {
        this.Invoke((MethodInvoker)delegate
        {
            this.updater(MSG, finish);
        });
    }
    else
    {
        this.updater(MSG, finish);
    }
}

private void updater(string MSG, bool finish = false) // NOT thread safe, thus the private (don't call directly)
{
    this.label1.Text = MSG;
    if (finish) { this.Close(); }
}