如何线程安全调用DataGridView

时间:2014-05-08 16:54:30

标签: c# multithreading datagridview thread-safety

我尝试使用计时器每秒连接并向DatagridView1显示数据库。我是C#的新手,所以我对线程系统感到困惑。我尝试从计时器调用munculkantabel()并始终返回跨线程操作无效:从除创建它的线程以外的线程访问控件。那么如何修复这段代码?

 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);
        }
    }

2 个答案:

答案 0 :(得分:0)

GUI组件与运行GUI消息泵的线程绑定。

从任何其他线程直接访问是未定义行为的道路(如果您运气好,其他一切......,某些事情可能会起作用。)

相反,从工作线程(例如,响应于计时器事件)需要使用GUI的BeginInvoke(这是前一段的一个例外)方法控制在GUI线程上执行任何操作。

在您的代码中,替换

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

使用:

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

当然,任何依赖于对数据网格的更改的代码也可以类似地在GUI线程上运行,以便已知上述代码已经完成。在您的情况下,您不会直接受此影响,因为您没有清理数据库连接等。(答案:清除GUI线程上的连接等,或至少在GUI线程之后启动的任务中)上面的代码)。

另请注意,BeginInvoke也是&#34的例外情况;如果您已调用BeginABC,则必须致电EndABC以执行任何清理工作"规则:在这种情况下,不需要EndInvoke(并且记录如此)。

答案 1 :(得分:0)

您需要做的只是使用WinFormsWPF的正确计时器。