我如何使用Backgroundworker C#更改其他形式的标签?

时间:2018-09-09 13:11:24

标签: c# multithreading backgroundworker

我的项目c#中有2个表单(formA和formB),当我单击formA中的按钮时,我想在backgroundworker中运行某些进程。

我可以从backgroundworker更新为FormB中的标签吗? 这是formA中的代码

        private void button1_Click_1(object sender, EventArgs e)
    {
        backgroundWorker1.RunWorkerAsync();
    }

    private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
    {
        Stimulus stimulus = new Stimulus();
        Stopwatch watch = new Stopwatch();
        stimulus.Show();
        stimulus.Invoke((MethodInvoker)delegate { stimulus.perbaharuiStimulus("+"); });
        watch.Start();
        do
        {

        } while (watch.Elapsed.Seconds != 2);
        watch.Restart();
        stimulus.Invoke((MethodInvoker)delegate { stimulus.perbaharuiStimulus("MAJU"); });
        do
        {

        } while (watch.Elapsed.Seconds != 6);
        watch.Restart();
        stimulus.Invoke((MethodInvoker)delegate { stimulus.perbaharuiStimulus(""); });
        do
        {

        } while (watch.Elapsed.Seconds != 2);
        watch.Stop();
        stimulus.Close();
    }

以及这是FormB中的代码

        public Stimulus()
    {
        InitializeComponent();
        FormBorderStyle = FormBorderStyle.None;
        WindowState = FormWindowState.Maximized;
    }
    public void perbaharuiStimulus(string stimulus)
    {
        this.Invoke((MethodInvoker)delegate
        {
            lbStimulus.Text = stimulus;
        });
    }

谢谢您的关注。

3 个答案:

答案 0 :(得分:2)

您可以像下面那样更改代码,这样就可以正常工作。

  1. 将perbaharuiStimulus代码更改为

    lbStimulus.Text = stimulus;
    
  2. WorkerReportsProgress更改为True

  3. backgroundWorker1_DoWork更改为以下

        Stimulus stimulus = new Stimulus();
        Stopwatch watch = new Stopwatch();
        backgroundWorker1.ReportProgress(1, stimulus);
        watch.Start();
        do
        {
    
        } while (watch.Elapsed.Seconds != 2);
    
        watch.Restart();
        backgroundWorker1.ReportProgress(2, stimulus);
        do
        {
    
        } while (watch.Elapsed.Seconds != 6);
    
        watch.Restart();
        backgroundWorker1.ReportProgress(3, stimulus);
        do
        {
    
        } while (watch.Elapsed.Seconds != 2);
        watch.Stop();
    
        stimulus.Invoke((MethodInvoker)delegate { stimulus.Close(); });
    
  4. 添加backgroundWorker1_ProgressChanged事件并在其中添加以下代码

    private void backgroundWorker1_ProgressChanged(object sender, ProgressChangedEventArgs e)
    {
        Stimulus stimulus = ( Stimulus)e.UserState;
        if(e.ProgressPercentage==1)
            stimulus.perbaharuiStimulus("+");
        if (e.ProgressPercentage == 2)
            stimulus.perbaharuiStimulus("MAJU");
        if (e.ProgressPercentage == 3)
            stimulus.perbaharuiStimulus("");
    
        stimulus.Show();
    }
    

希望对您有帮助!

答案 1 :(得分:0)

您可以使用Invoke(...)从后台工作人员以任何形式更新标签,就像这样做一样。 (假设刺激是一个领域)。 调用一次Invoke就足够了。 Stimulus.Invoke在刺激形式的控制线程上执行委托。因此,您可以在调度线程时决定。我建议在perbarauiStimulus中进行此操作,因为这样可以减少有人忘记分派呼叫的机会。

但是您的代码存在一个潜在问题:

不要对经过的时间使用精确的比较。优先使用'> ='。由于您要处理的秒数很少会成为实际问题,但可能会导致无限循环。

如果stimulus不是字段,则必须在后台工作程序的Stimulus 外部实例中创建一个实例,因为如果您在worker方法中创建该实例,窗体将在后台工作线程上运行其消息循环。这样就无需使用后台工作程序,因为该操作现在可以从同步视图中同步运行。

答案 2 :(得分:0)

您不应该在后台线程中创建表单。这样做会将表单分配给那个线程而不是UI线程,这意味着表单现在与消息泵不在同一个线程上。

您可以通过在UI线程上调用实例化和查看表单来解决此问题,然后您接下来的Invoke调用应该可以工作。

Stimulus stimulus;

this.Invoke((MethodInvoker)delegate
{
    stimulus = new Stimulus();
    stimulus.Show();
});

//No need to invoke this since perbaharuiStimulus() calls Invoke() as well.
stimulus.perbaharuiStimulus("+");

//The rest of your code...

除此之外,您可以正确地进行所有操作。