title: Cross Threading issue with C# ProgressBar
body: <p>I'm creating a countdown timer that allows the user to choose a valid time, and once the countdown reaches zero, it plays a sound.</p>
  
  <p>I've instantiated a timer from the <code>System.Timers</code> namespace and set its <code>Interval</code> to <code>1</code> second. I convert the user-specified time to seconds, and decrement that value by <code>1</code> every time the <code>Timer.Elapsed</code> function hits. Once it reaches zero, that means the countdown has reached zero which means it's time to play the sound.</p>
  
  <p>However, whenever it doesn't reach zero, I decrement the time value by <code>1</code> and I also want to increment the <code>ProgressBar</code> by using the <code>progressbar.Increment</code> function.</p>
  
  <p>Unfortunately, whenever I do this, it gives me an exception having to do with multithreading issues. I know what is wrong, but I am not sure how to fix it. Do I need to start the <code>timer.Elapsed</code> function on a new thread?</p>
  
  <p>The error is:</p>
  
  <blockquote>
    <p>Cross-thread operation not valid: Control 'CountdownProgress' accessed
    from a thread other than the thread it was created on.</p>
  </blockquote>
  
  <p>Also, any tips on better programming habits are welcome as well.
  Many thanks!</p>
  
  <p>Here is the code:</p>
  
  <pre><code>using System;
  using System.Collections.Generic;
  using System.ComponentModel;
  using System.Data;
  using System.Drawing;
  using System.Linq;
  using System.Text;
  using System.Windows.Forms;
  using System.Timers;
  using System.Media;
  using System.Diagnostics;
  using System.Threading;
  
  namespace WindowsFormsApplication1
  {
      public partial class Form_CDA : Form
      {
          public Form_CDA()
          {
              InitializeComponent();
          }
  
          private bool m_CountdownActive; // declare global variables and instantiate timer.
          private bool m_Cancelled;
          public decimal seconds;
          public decimal minutes;
          public decimal hours;
          public decimal time;
          public System.Timers.Timer timer = new System.Timers.Timer();
  
          private void Form_CDA_Load(object sender, EventArgs e)
          {
              m_Cancelled = false;
              timer.AutoReset = false;
              timer.Interval = 0;
              m_CountdownActive = false;
              richTextBox1.Text = "Hello, please select an hour between 0 and 100, a minute between 0 and 59, and a second between 0 and 59. The countdown timer will play a sound when finished.";
              btn_Cancel.Enabled = false;
              seconds = 0;
              minutes = 0;
              hours = 0;
              time = 0;
              m_StatusBar.Text = "Program properly loaded, waiting for user input"; // initialize variables.
          }
  
          private void btn_SetCountdown_Click(object sender, EventArgs e)
          {
              seconds = numUpDown_Seconds.Value;
              minutes = numUpDown_Minutes.Value;
              hours = numUpDown_Hours.Value;
              time = (hours * 3600) + (minutes * 60) + seconds; // calculate the total time in seconds.
              if (time != 0) // if time is not zero, start timer and set up event handler timer.elapsed.
              {
                  timer.Interval = 1000;
                  timer.AutoReset = true;
                  timer.Start();
                  timer.Elapsed += new ElapsedEventHandler(timer_Elapsed);
                  CountdownProgress.Maximum = (int)time;
                  CountdownProgress.Minimum = 0;
                  CountdownProgress.Value = 0;
              }
              else
              {
                  m_StatusBar.Text = "Invalid selection of times. Try again.";
                  return;
              }
              DateTime dt = DateTime.Now;
              dt.AddSeconds((double)time);
              Label_Countdown.Text = "Finishing time: " + dt.ToString(); // display end time to user.
              m_CountdownActive = true;
              btn_Cancel.Enabled = true;
              btn_SetCountdown.Enabled = false;
              numUpDown_Hours.Enabled = false;
              numUpDown_Minutes.Enabled = false;
              numUpDown_Seconds.Enabled = false; // disable controls.
              m_Cancelled = true;
              m_StatusBar.Text = "Timer set to " + numUpDown_Hours.Value.ToString() + " hours, " + numUpDown_Minutes.Value.ToString() + " minutes, " + numUpDown_Seconds.Value.ToString() + " seconds.";
          }
  
          void timer_Elapsed(object sender, ElapsedEventArgs e)
          {
              if (time == 0)
              {
                  m_StatusBar.Text = "Countdown Finished";
                  SoundPlayer soundPlayer = new SoundPlayer(@"C:\Users\marupakuuu\Desktop\New stuff\doorbell.wav");
                  soundPlayer.Play(); // play sound.
                  timer.Stop();
                  return;
              }
              else
              {
                  time = time - 1;
                  CountdownProgress.Increment(1); // exception occurs here; multithreading issues.
              }
          }
  
          private void btn_Cancel_Click(object sender, EventArgs e)
          {
              // if user wishes to stop the countdown to start a new one.
              m_Cancelled = true;
              m_CountdownActive = false;
              btn_SetCountdown.Enabled = true;
              numUpDown_Seconds.Value = 0;
              numUpDown_Minutes.Value = 0;
              numUpDown_Hours.Value = 0;
              numUpDown_Hours.Enabled = true;
              numUpDown_Minutes.Enabled = true;
              numUpDown_Seconds.Enabled = true;
              btn_Cancel.Enabled = false;
              m_StatusBar.Text = "Countdown cancelled";
          }
      }
  }
  </code></pre>