Refresh DataGridView when updating data source
Asked Answered
F

8

74

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);
}
Fourposter answered 31/10, 2008 at 15:5 Comment(1)
Could you take a look at my answer and accept it if it's the most appropriate?Syndicate
M
50

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.

Musick answered 31/10, 2008 at 15:40 Comment(11)
This is the way I have been doing it for a long time and it seems to work the best. It causes all of your data bound controls to check to see if their data has been updated and then refresh if necessary.Respirator
cheers for validating that. i was hoping you could just change the datasource then perform a refresh of some kind. :P it just seemed like a logical solution. oh wellFourposter
What's the significance of using 'typeof(List)' instead of null?Polymerous
@GWLlosa, if you are using auto generated columns and you set the datasource to NULL it will clear the columns. By using typeof(List) it should maintain the column structure during the refresh. I would personally use AutoGenerateColumns = false; and create the columns on the first pass of the refresh. That way if the user resizes a column it won't toss out their change on refresh.Engorge
@Musick Why not use a BindingSource and then you can refresh on that which is so clean and tidy as opposed to re-binding as it were?Kalevala
@CodeBlend - Well, if you mean BindingSource.ResetBindings(), it just does not refresh the items for me. The DataSource property needs to be "cleared" and set again to see any changes. A working example with BindingSource would be much appreciated ;)Musick
@Musick There isn't anything wrong with 'clearing' as such but to just call one method to 'refresh' makes life so easy. Let me know what you think =) #7008861Kalevala
What's the problem of just setting dataGridView1.DataSource to the new data. This update the grid automatically without removing column's structure even when AutoGenerateColumns is true.Hurst
when using dgv1.rowEnter event with this solution. , it causes exception DataGridView rowEnter: “Index -1 does not have a value.” at Application.Run . .net internal bug. instead bind dgv .datasource = bindingsource ; bindingsource.datasurce = list . whenever you add remove to list. bindingsource.resetbindings(false);Firebreak
I have a custom class 'Chains' inherited from SortableBindingList. I was having issues with CurrencyManager errors when refreshing the data in this class. I added the following 2 lines before refreshing and setting BindingSource. This beautifully resolved the issue. dgvChains.DataSource = typeof(BindingSource); dgvChains.Refresh(); Thanks to @Musick for his solution.Harlamert
@CodeBlend, please see my answer above.Harlamert
P
59

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.

Polymerous answered 13/7, 2009 at 11:42 Comment(4)
This is a good suggestion. After that you just have to call .Refresh() for the datagridview to refresh it's data displayed...Marjorymarjy
can refresh row by row using: bindingList.ResetItem(bindingList.IndexOf(item));Deliberation
.Refresh() just talks about the control redrawing, nothing to do with bindings unless I am very much mistaken! "Forces the control to invalidate its client area and immediately redraw itself and any child controls." Control.Refresh MethodKalevala
BindingList with BindingSource and using ResetBindings didn't work for me.Lisabeth
M
50

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.

Musick answered 31/10, 2008 at 15:40 Comment(11)
This is the way I have been doing it for a long time and it seems to work the best. It causes all of your data bound controls to check to see if their data has been updated and then refresh if necessary.Respirator
cheers for validating that. i was hoping you could just change the datasource then perform a refresh of some kind. :P it just seemed like a logical solution. oh wellFourposter
What's the significance of using 'typeof(List)' instead of null?Polymerous
@GWLlosa, if you are using auto generated columns and you set the datasource to NULL it will clear the columns. By using typeof(List) it should maintain the column structure during the refresh. I would personally use AutoGenerateColumns = false; and create the columns on the first pass of the refresh. That way if the user resizes a column it won't toss out their change on refresh.Engorge
@Musick Why not use a BindingSource and then you can refresh on that which is so clean and tidy as opposed to re-binding as it were?Kalevala
@CodeBlend - Well, if you mean BindingSource.ResetBindings(), it just does not refresh the items for me. The DataSource property needs to be "cleared" and set again to see any changes. A working example with BindingSource would be much appreciated ;)Musick
@Musick There isn't anything wrong with 'clearing' as such but to just call one method to 'refresh' makes life so easy. Let me know what you think =) #7008861Kalevala
What's the problem of just setting dataGridView1.DataSource to the new data. This update the grid automatically without removing column's structure even when AutoGenerateColumns is true.Hurst
when using dgv1.rowEnter event with this solution. , it causes exception DataGridView rowEnter: “Index -1 does not have a value.” at Application.Run . .net internal bug. instead bind dgv .datasource = bindingsource ; bindingsource.datasurce = list . whenever you add remove to list. bindingsource.resetbindings(false);Firebreak
I have a custom class 'Chains' inherited from SortableBindingList. I was having issues with CurrencyManager errors when refreshing the data in this class. I added the following 2 lines before refreshing and setting BindingSource. This beautifully resolved the issue. dgvChains.DataSource = typeof(BindingSource); dgvChains.Refresh(); Thanks to @Musick for his solution.Harlamert
@CodeBlend, please see my answer above.Harlamert
S
32

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.

Syndicate answered 3/12, 2016 at 23:54 Comment(4)
This answer should have received the correct answer flag. My vote goes here.Timberlake
@jsa: Unfortunately, OP haven not been visiting SO since 2009.Syndicate
Definitely the best answer - a pity the other got so many upvotes, but it has had a lot longer to collect them, to judge by dates!Lotuseater
good solution, bindingsource[e.RowIndex]=mylist; worked for me very well , instead of datagridview.Refresh(); thank you @AlexanderSindysine
D
3

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;
Desperado answered 11/5, 2015 at 18:55 Comment(0)
B
0

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()

Beauchamp answered 11/5, 2015 at 18:23 Comment(0)
D
0

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);
Deadfall answered 14/8, 2015 at 20:24 Comment(0)
K
0

Just delete all Rows and fill it after deleting:

BindingList<ItemState> itemStates = new BindingList<ItemState>();
datagridview1.Rows.Clear();

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

datagridview1.DataSource = itemStates;
Thread.Sleep(500);
Kortneykoruna answered 6/7, 2022 at 14:20 Comment(0)
E
-5

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);
}
Extensor answered 31/10, 2008 at 15:10 Comment(1)
DataBind() is an ASP .Net method for databound controls.Denunciate

© 2022 - 2024 — McMap. All rights reserved.