0

I try to connect and show database to DatagridView1 every second using timer. Im new in C# so I confuse about threading system. I try to call munculkantabel() from timer and it is always return that Cross-thread operation not valid: Control accessed from a thread other than the thread it was created on. So How to fix this code?

 public void buattimer()
    {
        System.Timers.Timer aTimer = new System.Timers.Timer();
        aTimer.Elapsed += new ElapsedEventHandler(backgroundWorker1_DoWork);
        aTimer.Interval = 1000;
        aTimer.Enabled = true;
    }

    public void backgroundWorker1_DoWork(object source, ElapsedEventArgs e)
    {
        Thread thh = new Thread(munculkantabel);
        thh.Start();
    }


string constring = "datasource=localhost;port=3306;username=root;password=;convert zero datetime=True";
    public void munculkantabel()
    {
        MySqlConnection conDataBase = new MySqlConnection(constring);
        MySqlCommand cmdDataBase = new MySqlCommand(" select * from konsentrasi.okedeh ;", conDataBase);
        try
        {
            MySqlDataAdapter sda = new MySqlDataAdapter();
            sda.SelectCommand = cmdDataBase;
            DataTable dbdataset = new DataTable();
            sda.Fill(dbdataset);
            BindingSource bSource = new BindingSource();

            bSource.DataSource = dbdataset;
            dataGridView1.DataSource = bSource;
            sda.Update(dbdataset);
        }
        catch (Exception ex)
        {
            MessageBox.Show(ex.Message);
        }
    }
Rhizudeen
  • 47
  • 11

2 Answers2

0

GUI components are tied to the thread running the GUI's message pump.

Direct access from any other thread is the road of undefined behaviour (some things might appear to work if you're luck, everything else …).

Rather, from the worker thread (eg. in response to the timer event) needs to use the BeginInvoke (this is the one exception to the previous paragraph) method of the GUI control to execute any manipulation on the GUI thread.

In your code, replace

bSource.DataSource = dbdataset;
dataGridView1.DataSource = bSource;
sda.Update(dbdataset);

with:

dataGridView1.BeginInvoke(() => {
  bSource.DataSource = dbdataset;
  dataGridView1.DataSource = bSource;
  sda.Update(dbdataset);
});

Of course, any code that depends on the changes to the data grid much also be similarly run on the GUI thread, in such a way that the above code is known to have completed. In your case, you're not directly affected by this because you are not cleaning up the database connection etc. (Answer: cleanup the connection etc. on the GUI thread, or at least in a task launched from the GUI thread after the above code).

Note also, that BeginInvoke is also the exception to the "if you've called BeginABC you must call EndABC to perform any cleanup" rule: in this case the EndInvoke is not needed (and is documented as such).

Richard
  • 106,783
  • 21
  • 203
  • 265
  • I try to replace but it says Error 1 Cannot convert lambda expression to type 'System.Delegate' because it is not a delegate type. What's wrong? – Rhizudeen May 08 '14 at 17:16
  • @tzudin Try casting to `Delegate` (there is something odd about the delegate types that the compiler cannot see the types `System.Delegate` and `System.Action` are compatible). – Richard May 09 '14 at 07:51
0

All you need to do is use the right timer for WinForms or WPF.

Slugart
  • 4,535
  • 24
  • 32