Hi
I have a WinGrid that is bound to a BindingSource and has an 'add row' at the bottom of the entries. I am instantiating a new object in the BindingSource's AddingNew when a new object is required.
If the user has entered the Add Row but has not made any changes, when they click or tab away, the data in the row is cleared and the row is blank again. In normal operation, this works beautifully and is exactly the behaviour I want for the application.
My problem is that the form's 'Save' button is on the UltraToolbarsManager toolbar. If the focus is on the unmodified Add Row when 'Save' is clicked, the Add Row does not disappear in the normal way and the app attempts to save the empty row.
I know that clicking a toolbar button does not normally take focus or cause validation. I have tried moving focus in code with a SelectNext, which does get around the problem but I don't like this as a solution and wondered if there was a setting that I could use that would improve things. We are forcing validation of the active control on toolbar_click so if we could somehow make use of this, that would be good.
Thanks in advance.
Hi,
Just to be clear, you are saying that if the focus is on the TemplateAddRow in the grid and you click your ToolBar button, which presumably calls UpdateData on the grid, the row gets saved to the underlying data source - even though not changes have been made to it?
That doesn't sounds like correct behavior to me. What version of the grid are you using? Do you have the latest service release?
Hi Mike
I'm using 2008 vol 3 (version 8.3.20083.2039 of Infragistics2.Win.UltraWinGrid.v8.3.dll).
The new row is saved into the underlying datasource regardless of whether I click on the ToolBar button. Once the row exists in the grid, it also exists in the datasource. What happens on lost focus, is that this row is removed from the underlying datasource, which is the bit thatisn't happening when I click the ToolBar button.
Yes, I'm calling UpdateData and as you say, this means that edits to an existing row get committed. However, it doesn't remove the unmodified add row.
I'm doing the following at the moment:
MdiChild.GetType.InvokeMember("ValidateActiveControl", Reflection.BindingFlags.NonPublic Or Reflection.BindingFlags.InvokeMethod Or Reflection.BindingFlags.Instance, Nothing, MdiChild, New Object() {False})EntriesGrid.UpdateData()Me.SelectNextControl(Me.ActiveControl, True, True, True, True) Me.SelectNextControl(Me.ActiveControl, False, True, True, True)
The first call to SelectNextControl causes the Add Row to be removed.
Okay, I think maybe I was a little confused here about what the problem is.
I just tested this out. I created a grid bound to a DataTable with one row and I set AllowAddNew to TemplateOnBottom.
I added a Toolbar with a button and this code:
this.ultraGrid1.PerformAction(UltraGridAction.ExitEditMode, false, false); this.ultraGrid1.UpdateData(); Debug.WriteLine(dt1.Rows.Count);
I also added a button to the form, just to have something to lose focus to.
So I run this application and I see 2 rows in the grid. The first row is the "real" data row. The second is the TemplateAddRow.
I then click into the TemplateAddRow and make no changes. At this point, the TemplateAddRow becomes a regular AddNewRow. This row is added to the DataTable, because that's how the DataTable works. But this is not a "real" row and has not been committed to the data - it's still an AddNew row.
Not I click my toolbar button. At this point, nothing essentially happens. The grid looks the same, focus is still on the TemplateAddRow and the Datatable rows count is still 1 (the Count does not include the AddNewRow).
The AddNewRow probably still exists in the table since the grid still has focus on the AddNewRow. But that's not a problem.
Not I click on the button, just so the grid loses focus. At this point, the grid gets it's position updated by the DotNet BindingManager, and the first row becomes active and the AddRow reverts back to a TemplateAddRow.
All of this seems fine and correct to me. Are you getting some different results?
Thanks very much for your efforts with this.
I guess the significant difference is that I am binding to a Collection (Of T) (actually a class that inherits from a Collection(Of T)) so there isn't a concept of an 'uncommitted row'.
Ah, okay. That makes sense. Try using (inherting from) BindingList (Of T), instead.
Initially, I thought changing to a BindingList had solved the problem, but I had removed my focus changing code from the wrong form and when I noticed this had happened, realised that using BindingList doesn't make any difference.
After clicking on the Toolbar, the item is still in the list and so an attempt is made to persist it to the database.
I thought perhaps I could check each element for being "uncommitted" to the BindingList, but there doesn't seem to be any way of distinguishing in the BindingList whether an element is a "NewRow" in the way that you talk about it in your DataTable example.
Hi Mike. You have an "AfterRowInsert" even that its fired when enter in a template mode. I use this event to make my work, but I need an BeforeRowDeleted event to erase my work. How can I do it without implements an Interface ?
Hi Mike,
Yes, it worked for me as you describe too. I got the EndNew calls but not the CancelNew.
Because EndNew is for committing the row and CancelNew is for rolling back, it's the CancelNew I need. EndNew doesn't provide me with any more information than I have already (because I am explicitly instantiating the row anyway).
I think your suggestion of the row keeping track of whether any changes have been made is the best solution, so I'll implement that.
I just tried this out and it worked fine for me. You don't have to do anything to the grid.
If I click into the TemplateAddRow, the ICancelAddNew.EndNew method get called to let me know that a new row was added. I don't need to do anything in here, so I left my implementation blank.
If I then click a toolbar button and call UpdateData on the grid, nothing happens. The TemplateAddRow just stays there and does nothing. The item exists in the list at this point, but it's in a sort've semi-added state. It exists in the BindingList, but it's not really a committed row. I'm not entirely sure how you are supposed to deal with this situation. You need to have some way to know about the state of this row. You can trap EndNew to determine that the row was added and is currently an AddNew row so that you know to ignore it when saving your data. But I'm not sure how you know when the row is committed and becomes a "real" row.
Perhaps the row itself needs to keep track of whether or not it has any changes in it. Then you don't need to handle EndNew. When you go to update the back end from your list, you ignore any rows that have no changes.
I have tried your suggestion and implemented ICancelAddNew on my collection class, but the CancelNew method doesn't get called. It isn't called in the toolbar click situation and it isn't called if the grid loses focus normally.
Do I have to also set properties on the Grid? Or do anything other than simply implementing the interface on my class?
Hm... I thought that would work.
If not, then my guess is that you need to implement ICancelAddNew on your collection class, as well.
Alternately, you could implement IEditableObject on the class that your list contains. But ICancelAddNew is probably a lot easier.