Nonblocking update to a DataGridView

♀尐吖头ヾ 提交于 2019-12-24 07:07:03

问题


I understand how to use delegates to update controls on the main control thread, works like a charm. My problem here is if I'm adding a large DataSet (say 2000 items) to a bound DataGridView, it takes 5-8 seconds for the grid to populate and during that 5-8 seconds the whole GUI is locked. How can I update the DataGridView such that it doesn't lock the user interface?

To be clear, the problem isn't that I'm doing a slow query to a database and the UI is blocking on that, I already have the DataSet object[] and adding the array of objects to a BindingList<object> which the DataGrid is bound to so:

BindingList<object> dataProvider = new BindingList<object>();
DataGridView gridView = new DataGridView();
gridView.DataSource = dataProvider;

// ...stuff happens...

object[] source = dataSet; //of 2000 items
foreach (object item in source) {  //this foreach blocks
    dataProvider.Add(item);
}

I tried various things (that I knew wouldn't work but figured I'd see) like creating a delegate that did the dataProvider.Add(), but that didn't matter since it still had to happen on the control thread.

A couple good suggestions revolved around building the BindingList first and then setting the gridView.DataSource. While this works (it updates the grid instantly), the only way I see to add more data is to create another new BindingList, do a gridView.DataSource.copyTo() (to get the existing data) and add the new data on top of that, then set the gridView.DataSource to the new BindingList. This won't work for me since the objects in my list are not static, they are each uploading data to a server asynchronously, and copying them to a new BindingList would cause problems.


回答1:


You are adding records while the GridView is linked to the DataSource. This means it will update the layout each time.

How about you first fill your DataSource and only then set the DataSource property?

gridView.DataSource = null;
...stuff happens...

object[] source = dataSet; //of 2000 items
foreach (object item in source) {  //this foreach blocks
    dataProvider.Add(item);
}

gridView.DataSource = dataProvider;

The foreach loop could go to another thread but I don't think you will need that.




回答2:


Like Nick said BackgroundWorker is probably your best bet.

Here is a very simple example

public partial class Form1 : Form
{
    BackgroundWorker b = new BackgroundWorker();

    public Form1()
    {
        InitializeComponent();
        b.RunWorkerCompleted += new RunWorkerCompletedEventHandler(b_RunWorkerCompleted);
        b.DoWork += new DoWorkEventHandler(b_DoWork);
    }

    void b_DoWork(object sender, DoWorkEventArgs e)
    {
        // build dataset here and assigning it to results
        e.Result = dataset;            
    }

    void b_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
    {
        // assign the dataset you built in DoWork in the gridview and update it
        dataGridView1.DataSource = e.Result;
        dataGridView1.Update();
    }

    private void button1_Click(object sender, EventArgs e)
    {
        b.RunWorkerAsync();
    }
}



回答3:


Look into using a BackgroundWorker. I don't know much about them myself, but a little searching on Google reveals that as a good possibility.



来源:https://stackoverflow.com/questions/1296340/nonblocking-update-to-a-datagridview

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!