2
votes

So I have this C# application that is getting values (6 variables) from Arduino. Initially I used a timer which calls some read functionts every 100ms but it hangs my UI and responds a little heavy. I want to use a backgroundworker which continuously reads those variables. I put those read calls in DoWork method and I put the values in variables from C# and assign them in a label or something. But it doesn't work. (sorry for my english)

namespace testtemp
{
    public partial class tempreaderform : Form
    {
        public tempreaderform()
        {
            InitializeComponent();
        }

communicator comport = new communicator();
Boolean portConnection = false;
String red_light1;

private void button1_Click(object sender, EventArgs e)
        { 
            if (comport.connect(57600, "I'M ARDUINO", 4, 8, 16))
            {
                label1.Text = "Connection Successful - Connected to  "+comport.port;
                portConnection = true;
                backgroundWorker1.RunWorkerAsync(); // I am not sure if here I should start the backgroundworker.
            }
            else
            {
                label1.Text = "Not connected . . . ";
                portConnection = false;
            }
        }

        private void groupBox1_Paint(object sender, PaintEventArgs e)
        {
            Graphics ellipse1 = groupBox1.CreateGraphics();

            Brush red_on = new SolidBrush(Color.Red);
            Brush red_off = new SolidBrush(Color.DarkRed);

            label2.Text = "Red : " + red_light1; //Here is a label which I want to show "1" if "red_light1" is "1" and "0" if "red_light1" is "0"

            if (red_light1 == "1") ellipse1.FillEllipse(red_on, 250, 133, 24, 24);
                            else ellipse1.FillEllipse(red_off, 250, 133, 24, 24); // Here is what I really want to do (the label.Text part was only to see the value) I want to color a ellipse depending on "red_light1" value.

        }



private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
        {
            while (true)
            {
                red_light1 = comport.message(4, 8, 32);
            }
        }
}
}
}

NOTE: I tryied this "label1.Text = red_light1" in DoWork method but it says that I can't give values to variables created in another thread, something like this.

2
Do you put backgroundWorker1_DoWork in another thread? - Thealon
I am not sure that I understand you. I do this frist time. I believed that what code I put in DoWork method it will "work" automatically in another thread. - user3672802
Well this while loop will never end therefor it will be stuck in there for ever. Please take a look here: msdn.microsoft.com/en-us/library/cc221403%28v=vs.95%29.aspx . - Thealon

2 Answers

1
votes

The "problem" is that the backgroundworker lives an another thread and you're trying to use in in the UI thread. And the message doesn't get communicated there.

There are three options:

  1. To use RunWorkerCompleted event: you have to use a timer to run backgroundworker every X ms.

    private void timer1_Tick(object sender, EventArgs e) {
      this.backgroundworker.RunWorkerAsync();
    }
    
    
    private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
      e.Result = comport.message(4, 8, 32);
    }
    
    private void backgroundWorker1_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e) {
      label2.Text = e.Result.ToString();
    }
    
  2. Use BeginInvoke to set the text

    private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
    {
        while (true)
        {
            this.BeginInvoke((Action)(() => { label2.Text = comport.message(4, 8, 32); });
    
           // add some delay here as well...
        }
    }
    
  3. Use Task instead of backgroundworker and call it in the timer.

    private void timer1_Tick(object sender, EventArgs e) {
      Task.Run(() => {
        this.BeginInvoke((Action)(() => { label2.Text = comport.message(4, 8, 32); });
       });
    }
    
1
votes

You can use the ReportProgress event:

  1. Set WorkerReportsProgress to true

  2. Write the event handler:

    private void backgroundWorker1_ProgressChanged(object sender, ProgressChangedEventArgs e)
    {
        String mytext = e.UserState as String;
        myLabel.Text = mytext;
    }
    
  3. Call the function inside the dowork

    private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
    {
        BackgroundWorker bgw = sender as BackgroundWorker;
        String receivedtext;
        while (true)
        {
            myreceivedtext = comport.message(4, 8, 32);
            bgw.ReportProgress(0, myreceivedtext);
            System.Threading.Thread.Sleep(100);
        }
    }