使用 sqldatareader 从另一个线程逐行填充 DataGridView

Posted

技术标签:

【中文标题】使用 sqldatareader 从另一个线程逐行填充 DataGridView【英文标题】:Populate DataGridView from another thread row by row using sqldatareader 【发布时间】:2012-11-01 13:41:31 【问题描述】:

我正在尝试执行一些需要很长时间并返回很多行的 SQL 查询,这就是我使用 SqlDataReader 来返回行的原因。

我在单独的线程中执行查询,因此在返回行时 UI 将可用。

我还有一个数据表,我用 SqlDataReader 填充,DataTable 绑定到 BindingSource,BindingSource 绑定到 DataGridView。

问题是DataGridView似乎无法将DataTable的列绑定到DataGridView中的Columns,网格中的所有单元格都显示为空白。即使使用 AutoGenerateColumns=true,也不会显示数据!

以下是与我的问题非常相似的示例代码:

public partial class Form2 : Form

    BindingSource binding;
    DataTable dt = new DataTable();
    DataGridView dgv;

    public Form2()
    
        InitializeComponent();

        binding = new BindingSource();
        binding.DataSource = dt;

        dgv = new DataGridView();
        dgv.Columns.Add("Column1", "Column1");
        dgv.Columns[0].DataPropertyName = "Column1";
        dgv.AutoGenerateColumns = false;
        dgv.DataSource = binding;
        dgv.Click += new EventHandler(dgv_Click);
        this.Controls.Add(dgv);

        dostuff();  // ON FIRST TRY 5 ROWS SHOWN
    

    void dgv_Click(object sender, EventArgs e)
    
        dostuff();  // ON SECOND RUN EVERYTHING IS CLEARED!
    

    void dostuff()
                
        dgv.DataSource = null;
        dt.Rows.Clear();
        dt.Columns.Clear();
        dgv.DataSource = binding;

        BackgroundWorker bgw = new BackgroundWorker();
        bgw.DoWork += new DoWorkEventHandler(bgw_DoWork);
        bgw.RunWorkerAsync();

    

    void bgw_DoWork(object sender, DoWorkEventArgs e)
    
        dt.Rows.Clear();
        dt.Columns.Clear();

        dt.Columns.Add("Column1");

        for (int i = 0; i < 5; i++)
        
            DataRow r = dt.NewRow();
            r[0] = i;
            dt.Rows.Add(r);
        
    

【问题讨论】:

【参考方案1】:

bgw_DoWork方法结束时需要刷新DataGridView,并且需要使用Invoke,因为Refresh方法必须在UI线程上运行。这是修改后的bgw_DoWork 方法:

void bgw_DoWork(object sender, DoWorkEventArgs e)

    dt.Rows.Clear();
    dt.Columns.Clear();

    dt.Columns.Add("Column1");

    for (int i = 0; i < 5; i++)
    
        DataRow r = dt.NewRow();
        r[0] = i;
        dt.Rows.Add(r);
    

    dgv.Invoke((MethodInvoker) delegate()  dgv.Refresh(); );

【讨论】:

我为跨线程控制修改找到的最佳解决方案是你的。谢谢。【参考方案2】:

您可以在DataGridView 中创建列,并将每个DataGridViewColumnDataPropertyName 设置为DataTable 中相应列的名称。如图所示:http://msdn.microsoft.com/en-us/library/system.windows.forms.datagridviewcolumn.datapropertyname.aspx

【讨论】:

我已经做到了。不幸的是,您的答案与从另一个线程填充数据无关..

以上是关于使用 sqldatareader 从另一个线程逐行填充 DataGridView的主要内容,如果未能解决你的问题,请参考以下文章

从另一个MyISAM表中自动加载MEMORY表

为啥这些静态函数不按预期从另一个线程返回?

使用线程从另一个成员函数调用一个成员函数

从另一个线程访问 UI 线程的视图

从另一个线程发出信号是否安全?

信号没有从另一个线程调用槽