Problem:
I am having problems getting the WinGrid to update after I reorder the BindingList that is bound to the grid.
Background:
I have a WinGrid with a BindingSource as its data source.
ultraGrid1.DataSource = BindingSource
I am using the BindingSource so that I can properly notify the grid that values in the BindingList objects have changed using INotifyPropertyChanged.
The BindingSource has a DataSource of a BindingList<mySimpleObject>
BindingSource.DataSource = BindingList<mySimpleObject>
I have 15 rows in the grid that are number sequentially from 1 – 15:
I select the first row and drag/drop it down between the 8th and 9th rows:
I added code to loop through my BindingList<mySimpleObject> to write out the sequence numbers. Before the changes from the move, this is the ordering of the items in my BindingList:
****************** Before Move
Seq: 1
Seq: 2
Seq: 3
Seq: 4
Seq: 5
Seq: 6
Seq: 7
Seq: 8
Seq: 9
Seq: 10
Seq: 11
Seq: 12
Seq: 13
Seq: 14
Seq: 15
Now I need to reorder the items in the list. I first store the mySimpleObject that I am moving in a local variable. Then I remove the item from the BindingList<mySimpleObject>:
BindingList.Remove(objectBeingMoved);
Next, I insert the object into the correct location:
BindingList.Insert(locIndex, objectBeingMoved);
After this, I loop across the BindingList again, writing out the sequence numbers. I get this output, which is what I would expect:
****************** After Move
My problem, though, is this:
As you can see, even though the sequence of the mySimpleObject items in the BindingList are ordered as I would expect when looping through the list, the moved item is moved all the way to the bottom of the grid. I am not doing any row refreshes, although I did try grid.Rows.Refresh(RefreshRow.ReloadData, true), but to no avail.
At this point, the only way that I can get the grid to refresh properly is to completely dump and then rebind the grid, like this:
Grid.DataSource = null;
Grid.DataSource = BindingSource;
There are at least two problems with this. First, It is terribly inefficient, and second it causes all of the sorts, filters, and column sizing to be reset.
One more data point… I wrote a simple application where I just put a grid and a button on a form to mimic this. I wanted to distill this to its simplest elements. Here is the relevant code:
public Form1()
{
InitializeComponent();
dataItems = new BindingList<DataItem>();
dataSource = new BindingSource();
dataSource.DataSource = dataItems;
}
private void Form1_Load(object sender, EventArgs e)
for (int i = 1; i < 11; i++)
var dataItem = new DataItem(i);
dataItems.Add(dataItem);
ultraGrid1.DataSource = dataSource;
private void ultraButton1_Click(object sender, EventArgs e)
DataItem temp = dataItems[0];
dataItems.RemoveAt(0);
dataItems.Insert(5, temp);
This code worked as I would have expected and the grid did reflect the new ordering of the objects in the BindingList.
Questions:
At this point, I am perplexed as to why my BindingList order looks correct, but the moved item in the BindingList always shows up at the bottom of the grid. So, I have three questions:
1. Does anyone know what might be causing my grief with the BindingList and the grid not being in sync?
2. If I have to rebind the BindingList to the grid after every drag/drop row operation (worst-case scenario), is there some easy way to save off the filters, column widths, etc so that I can reapply them after rebinding the BindingList?
3. (Best case scenario) – Is there some hidden functionality in the WinGrid that I have overlooked where I just flip a bit and row moving comes for free, automagically updating my BindingList for me? If not, why not? This would seem to be common functionality.
Hi,
I tried this out and it works fine for me. The row shows up in the correct place.I have attached my sample here so you can try it out and see if you get different results.
Having said that, it's generally not a good idea to rely on the grid rows being in the same order as the data source rows. This is not always true. Sorting, Filtering, and grouping will all change the order of the rows in the grid without affecting the data source. There is no reason why the data should always be in synch with the order of the rows in the data source - that's not a requirement for data binding.
Hi Mike, and thanks for the response.
I agree with you that the code sample I sent does work. It worked for me. However, in the context of my larger application, that same logic doesn't work and I think it is because I am assuming a one-to-one synchronized view between the BindingList data source for the grid and the view on the grid.
In my app, I have a grid with two bands and I have these drag/drop move scenarios:
1. Move row from Band[0] to Band[0]
2. Move row from Band[0] to Band[1]
3. Move row from Band[1] to Band [0]
4. Move row from Band[1] to Band [1]
After your reply, I have gone back and changed my code such that a drag/drop from position to position on the 0th band works every time. To do this, I am using Grid.Rows.Move(position, row). This works within the 0th band and makes scenario 1 work.
Now I am having problems with scenarios 2-4. Anytime that I deal with Band [1], I have problems, even if it is moving rows around within this band. My results are inconsistent, but mostly result in the moved row being pushed to the bottom of the grid. I have tried both moving the Rows with Grid.Rows.Move and changing the order of objects around in the child lists of my data objects. I have discovered that it looks like the Grid.Rows collection seems to only be a collection of rows from Band[0]. So, the thing that is working, moving items within Band [0] with Grid.Rows.Move, won't work for the child rows. This has led me to change the order of items in the underlying, bound collections with inconsistent results. It appears that I can move items from Band[0] to Band [1] with success by changing the order of the items in the BindingList of objects and their child object collections and then calling Grid.Rows.Refresh(RefreshRow.ReloadData, true);. However, moving from Band[1] to Band[0] or from Band[1] to Band[1] with this same methodology is inconsistent.
I have searched for other posts in the forum where others have encountered this issue and ran across a couple. I have also worked with a few more example programs to simplify this, but the samples are small and seem to work better than my larger program. I think it might be because of the filtering that I am applying.
What I need to know is what are the API rules for moving bound items from band-to-band. From my research and your help, I am seeing these rules emerge (although I am not 100% sure these are correct):
1. Move of row(s) within the top-most band should be done with grid.Rows.Move()
2. Move of row(s) from band-to-band must be accomplished by changing the underlying BindingList collections
a. grid.Rows.Refresh() must be called to reflect underlying BindingList collection changes
I am pretty sure that I am correct about rule 1, but 2 has me stumped because it works moving rows from band 0 to 1, but not the other way.
Any thoughts on what I am missing?
Thanks in advance,
Keith