66
votes

What is the best way to refresh a DataGridView when you update an underlying data source?

I'm updating the datasource frequently and wanted to display the outcome to the user as it happens.

I've got something like this (and it works), but setting the DataGridView.DataSource to null doesn't seem like the right way.

List<ItemState> itemStates = new List<ItemState>();
dataGridView1.DataSource = itemStates;

for (int i = 0; i < 10; i++) { 
    itemStates.Add(new ItemState { Id = i.ToString() });
    dataGridView1.DataSource = null;
    dataGridView1.DataSource = itemStates;
    System.Threading.Thread.Sleep(500);
}
8
Could you take a look at my answer and accept it if it's the most appropriate? - Alexander Abakumov

8 Answers

55
votes

I ran into this myself. My recommendation: If you have ownership of the datasource, don't use a List. Use a BindingList. The BindingList has events that fire when items are added or changed, and the DataGridView will automatically update itself when these events are fired.

49
votes

Well, it doesn't get much better than that. Officially, you should use

dataGridView1.DataSource = typeof(List); 
dataGridView1.DataSource = itemStates;

It's still a "clear/reset source" kind of solution, but I have yet to find anything else that would reliably refresh the DGV data source.

26
votes

The cleanest, most efficient and paradigm-friendly solution in this case is to use a System.Windows.Forms.BindingSource as a proxy between your list of items (datasource) and your DataGridView:

var itemStates = new List<ItemState>();
var bindingSource1 = new System.Windows.Forms.BindingSource { DataSource = itemStates };
dataGridView1.DataSource = bindingSource1;

Then, when adding items, use Add() method of BindingSource instead of your list's Add() method:

for (var i = 0; i < 10; i++)
{
    bindingSource1.Add(new ItemState { Id = i.ToString() });
    System.Threading.Thread.Sleep(500);
}

This way you adding items to your list and notifying DataGridView about those additions with the same line of code. No need to reset DataGridView's DataSource every time you make a change to the list.

It also worth mentioning that you can drop a BindingSource onto your form directly in Visual Studio's Forms Designer and attach it as a data source to your DataGridView there as well, which saves you a line of code in the above example where I'm doing it manually.

3
votes

Observablecollection :Represents a dynamic data collection that provides notifications when items get added, removed, or when the whole list is refreshed. You can enumerate over any collection that implements the IEnumerable interface. However, to set up dynamic bindings so that insertions or deletions in the collection update the UI automatically, the collection must implement the INotifyCollectionChanged interface. This interface exposes the CollectionChanged event, an event that should be raised whenever the underlying collection changes.

Observablecollection<ItemState> itemStates = new Observablecollection<ItemState>();

for (int i = 0; i < 10; i++) { 
    itemStates.Add(new ItemState { Id = i.ToString() });
  }
 dataGridView1.DataSource = itemStates;
0
votes

This is copy my answer from THIS place.

Only need to fill datagrid again like this:

this.XXXTableAdapter.Fill(this.DataSet.XXX);

If you use automaticlly connect from dataGridView this code create automaticlly in Form_Load()

0
votes

You are setting the datasource inside of the loop and sleeping 500 after each add. Why not just add to itemstates and then set your datasource AFTER you have added everything. If you want the thread sleep after that fine. The first block of code here is yours the second block I modified.

for (int i = 0; i < 10; i++) { 
    itemStates.Add(new ItemState { Id = i.ToString() });
    dataGridView1.DataSource = null;
    dataGridView1.DataSource = itemStates;
    System.Threading.Thread.Sleep(500);
}

Change your Code As follows: this is much faster.

for (int i = 0; i < 10; i++) { 
    itemStates.Add(new ItemState { Id = i.ToString() });

}
    dataGridView1.DataSource = typeof(List); 
    dataGridView1.DataSource = itemStates;
    System.Threading.Thread.Sleep(500);
0
votes

Alexander Abakumov's answer is the correct one. It solved every binding issue I had updating the underlying data and having the grid update.

Its easy to implement and modify any existing source code you have.

grdDetails.DataSource = new System.Windows.Forms.BindingSource { DataSource = OrderDetails };
-5
votes

Try this Code

List itemStates = new List();

for (int i = 0; i < 10; i++)
{ 
    itemStates.Add(new ItemState { Id = i.ToString() });
    dataGridView1.DataSource = itemStates;
    dataGridView1.DataBind();
    System.Threading.Thread.Sleep(500);
}